【问题标题】:Validation of objects/forms sent via AngularJS to Symfony2 REST API验证通过 AngularJS 发送到 Symfony2 REST API 的对象/表单
【发布时间】:2016-02-06 14:54:44
【问题描述】:

我正在使用带有 Restangular 库的 AngularJS 来处理用 Symfony2 + JMS Serializer + FOS Rest Bundle 编写的 Rest Api。

为了首先对用户实体执行 CRUD 操作,我让特定用户显示:

var User = Restangular.one('users', $routeParams.userId);

User.get()
    .then(function(response) {
        $scope.user = response;
    });

我收到这样的 JSON 响应:

{
    id: 1,
    firstName: "Howell",
    lastName: "Weissnat",
    job: {
        id: 1
        name: "Job Name"
    }
}

然后我想修改用户实体中的job 字段。在 Symfony 2 后端中,作业基本上是独立的实体(更像是值对象),具有与用户实体的 ORM 关系。

然后我通过 AngularJS 在前端修改用户,例如从选择框中的可用选项中选择作业。 $scope.user 的 JSON 表示形式如下所示:

{
    id: 1,
    firstName: "Howell",
    lastName: "Weissnat",
    job: {
        id: 2
        name: "Job Second Name"
    }
}

然后我用 Restangular 发出 PUT 请求:

$scope.user.save();

不幸的是 Symfony2 期望接收这样的对象:

{
    id: 1,
    firstName: "Howell",
    lastName: "Weissnat",
    job: 2
}

job: 2 基本上是指向 Job Entity 的 ID。

我成功地解决了在后端的UserType 类中创建 ViewTransformer 的问题。这基本上会将接收到的作业对象转换为具有 ID 值的标量整数。 symfony.com/doc/current/cookbook/form/data_transformers.html

$builder->get('job')->addViewTransformer

但是我觉得这不是正确的方法,我现在想不出更好的主意。将更复杂的对象发送到 Symfony2 RESTful 后端的最佳实践是什么?这只是一个简单的例子,但在我的应用程序中,User 类中的job 字段也可以包含Job 实体的集合。

【问题讨论】:

  • 我们基本上做的是,使用 jms 反序列化(使用教义对象构造函数,而不是 jms 的),将其合并到教义管理器中并刷新 .. 听起来太容易了,就这么简单!,你也可以简单地使用验证器服务,在刷新之前实际验证您的实体

标签: json angularjs rest symfony restangular


【解决方案1】:

我们使用的是这样的东西:

$entity = $this->get('jms_serializer')->deserialize($request->getContent(), $entityName, 'json');
if (!$entity) {
     throw new ApiException(Codes::HTTP_NOT_FOUND, null, 'entity with that id not found');
}

$violations = $this->get('validator')->validate($entity, $validationGroups);

if (count($violations) > 0) {

     return $violations;
}


$this->getDoctrine()->getManager()->merge($entity);
$this->getDoctrine()->getManager()->flush();

为您服务:

services:
    jms_serializer.doctrine_object_constructor:
          class:        %jms_serializer.doctrine_object_constructor.class%
          public:       false
          arguments:    ["@doctrine", "@jms_serializer.unserialize_object_constructor"]

    jms_serializer.object_constructor:
      alias: jms_serializer.doctrine_object_constructor

这基本上是确保 jms 从教义中获取实体,并将值应用于现有的实体,而不是创建新实体,并将值应用到新实体(并可能以一些空字段)

【讨论】:

  • 如果我理解正确你完全放弃了标准的 Symfony2 Form 对象?你不在控制器中使用 $form->submit() 或 $form->handleRequest() 吗? $form->isValid() 中的验证呢?
  • 确实,我完全放弃了表单,而不是 $form->isValid() 来检查数据是否有效,我们使用验证器服务来验证对象(这有点像形式也可以在幕后进行)
  • 另一个问题。如果用户提交了额外的数据——在编辑表单中没有提供,会发生什么?验证组是否处理?例如,有一个带有“name”和“lastName”的编辑表单,但用户也设法在请求中发送“gender”。如何防止该字段持续存在(FormType builder 有这种机制)?
  • 如果模型中不存在该字段将被忽略,如果模型中存在则将其持久化,除非您添加只读注解,或设置访问器注解,无需设置设置器,或者用虚拟属性注释覆盖它,或者以其他方式阻止它,否则,它将被持久化
  • 编辑,我必须重新检查,但你确定你不能只用排除组来处理这个吗?甚至可能通过反序列化和合并两次(所以它最终得到一个没有额外字段的版本,如果你明白我的意思吗?)反序列化,合并(错误的性别设置),序列化(性别现在消失了),合并(与新鲜,如此正确的性别).?肯定没有好的表现明智..!!
【解决方案2】:

在你的 UserFormType 中试试这个solution

$jobTransformer = new EntityToIdObjectTransformer($this->om, "AcmeDemoBundle:Job");
$builder
    ->add('firstName', 'text')
    ...
    ->add($builder->create('job', 'text')->addModelTransformer($jobTransformer))

【讨论】:

  • 哇,我的案例一直都在 Symfony2 文档中。感谢您指出了这一点。这是首选的解决方案,因为标准 FormType 没有像 @Sam 的解决方案那样被抛弃。
猜你喜欢
  • 2014-03-27
  • 2019-08-24
  • 1970-01-01
  • 2013-02-02
  • 1970-01-01
  • 2012-10-22
  • 2012-02-10
  • 1970-01-01
  • 2014-12-06
相关资源
最近更新 更多