从数据数组填充实体,无需表单/请求


Populate entity from data array without form/request

只是想知道是否可以只使用symfony表单处理的某些部分。例如,当通过generate:doctrine:crud创建CRUD操作时,我在控制器中得到如下内容(用于处理创建用户POST请求):

$entity = new User();
$form = $this->createForm(new UserType(), $entity,
        array(
        'action' => $this->generateUrl('user_create'),
        'method' => 'POST',
));
$form->handleRequest($request);
//Here I have a filled Entity

但我想要的是在一个更可重用的解决方案中实现这一点。目前,我的业务逻辑在一个名为UserModel的服务中。在这里,我还希望使用create方法来创建、验证和持久化一个新实体。很难,UserModel也应该可以通过控制台从一些命令脚本中调用,所以我可能不会总是有RequestForm

因此,从上面的代码中,我知道Symfony已经在根据UserType的定义以某种方式将数据填充到实体中,但如果没有FormRequest,而只是一些数据数组,我怎么能手动做到这一点呢
这样我就不必自己设置属性了。

编辑:验证对于填充实体来说没有问题,我稍后将在持久化数据之前对已填充的实体使用validator
对我来说同样重要的是,传递的related entity ids将被自动处理/加载。

您仍然可以使用Form组件,但不应该使用handleRequest,而应该直接使用submit

如果你很好奇,你应该在github上查找handleRequest的代码以及它的实际功能;你会看到它只是做了一些验证,从Request中获取数据,然后使用Form.的submit方法

因此,基本上,您只能对想要使用的数据使用submit方法。它甚至会验证您的实体。:)

更新

对于创建/更新相关实体的问题,如果你的关系有一个持久化/更新级联,它应该在你不做任何事情的情况下从自身展开,除了在你的主实体上持久化+刷新。

如果您不担心像处理验证之类的事情,您可以做一些像我所做的事情。

您可以定义一个特征,或者在实体类中包含fromArray函数。

trait EntityHydrationMethod
{
    public function fromArray($data = array())
    {
        foreach ($data as $property => $value) {
            $method = "set{$property}";
            $this->$method($value);
        }
    }
}

如果你定义了trait,你可以在你的实体中使用它,比如:

class User{
  use EntityHydrationMethod;
}

然后从你的用户模型中,你可以定义你的创建功能,比如:

public function create($data = array())
{
    $entity = new User();
    $entity->fromArray($data);
    return $entity;
}

-已更新-

当你更新你的问题时。您可以通过定义一个trait或在EntityRepository类中包含createFromArray函数来实现这一点。

trait RepositoryCreateMethod {
    public function createFromArray($data)
    {
        $class = $this->getClassName();
        $object = new $class();
        $meta = $this->getClassMetadata();
        foreach ($data as $property => $value) {
            $v = $value;
            if(!empty($value) && $meta->hasAssociation($property)) {
                $map = $meta->getAssociationMapping($property);
                $v = $this->_em->getRepository($map['targetEntity'])->find($value);
                if(empty($v)){
                    throw new 'Exception('Associate data not found');
                }
            }
            $method = "set{$property}";
            $object->$method($v);
        }
        return $object;
    }
}

如果你定义了trait,你可以在你的存储库中使用它,比如:

class UserRepository{
  use RepositoryCreateMethod;
}

然后你可以使用类似于来自控制器的调用:

$user = $this->getDoctrine()
             ->getRepository('YourBundle:User')
             ->createFromArray($data);