Symfony Sonata管理包一对多关系不保存外部ID
我对SonataAdminBunle与symfony 2.2的结合有一个问题。 我有一个项目实体和一个项目图像实体,并指定了这两个实体之间的一对多关系,如下所示:Symfony Sonata管理包一对多关系不保存外部ID,symfony,sonata-admin,Symfony,Sonata Admin,我对SonataAdminBunle与symfony 2.2的结合有一个问题。 我有一个项目实体和一个项目图像实体,并指定了这两个实体之间的一对多关系,如下所示: class Project { /** * @ORM\OneToMany(targetEntity="ProjectImage", mappedBy="project", cascade={"all"}, orphanRemoval=true) */ private $images; } clas
class Project
{
/**
* @ORM\OneToMany(targetEntity="ProjectImage", mappedBy="project", cascade={"all"}, orphanRemoval=true)
*/
private $images;
}
class ProjectImage
{
/**
* @ORM\ManyToOne(targetEntity="Project", inversedBy="images")
* @ORM\JoinColumn(name="project_id", referencedColumnName="id")
*/
private $project;
}
我已经配置了ProjectAdmin和ProjectMageAdmin:
class ProjectAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('title')
->add('website')
->add('description', 'textarea')
->add('year')
->add('tags')
->add('images', 'sonata_type_collection', array(
'by_reference' => false
), array(
'edit' => 'inline',
'inline' => 'table',
'sortable' => 'id',
))
;
}
}
class ProjectImageAdmin extends Admin
{
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('file', 'file', array(
'required' => false
))
;
}
}
问题在于,在数据库的project_image表中,project_id没有保存,而所有其他数据和图像都保存了。在其他任何地方都找不到有效的答案。虽然不相关,但我会稍微调整一下您的一对多注释:
class Project
{
/**
* @ORM\OneToMany(targetEntity="ProjectImage", mappedBy="project", cascade={"persist"}, orphanRemoval=true)
* @ORM\OrderBy({"id" = "ASC"})
*/
private $images;
}
回到正轨,您的注释和Sonata管理表单看起来不错,所以我很确定您在项目实体类中缺少了其中一个方法:
public function __construct() {
$this->images = new \Doctrine\Common\Collections\ArrayCollection();
}
public function setImages($images)
{
if (count($images) > 0) {
foreach ($images as $i) {
$this->addImage($i);
}
}
return $this;
}
public function addImage(\Acme\YourBundle\Entity\ProjectImage $image)
{
$image->setProject($this);
$this->images->add($image);
}
public function removeImage(\Acme\YourBundle\Entity\ProjectImage $image)
{
$this->images->removeElement($image);
}
public function getImages()
{
return $this->Images;
}
在你的管理课上:
public function prePersist($project)
{
$this->preUpdate($project);
}
public function preUpdate($project)
{
$project->setImages($project->getImages());
}
我解决这个问题的一种方法是通过一个定制的Sonata模型管理器手动设置所有反向边关联
<?php
namespace Sample\AdminBundle\Model;
class ModelManager extends \Sonata\DoctrineORMAdminBundle\Model\ModelManager
{
/**
* {@inheritdoc}
*/
public function create($object)
{
try {
$entityManager = $this->getEntityManager($object);
$entityManager->persist($object);
$entityManager->flush();
$this->persistAssociations($object);
} catch (\PDOException $e) {
throw new ModelManagerException('', 0, $e);
}
}
/**
* {@inheritdoc}
*/
public function update($object)
{
try {
$entityManager = $this->getEntityManager($object);
$entityManager->persist($object);
$entityManager->flush();
$this->persistAssociations($object);
} catch (\PDOException $e) {
throw new ModelManagerException('', 0, $e);
}
}
/**
* Persist owning side associations
*/
public function persistAssociations($object)
{
$associations = $this
->getMetadata(get_class($object))
->getAssociationMappings();
if ($associations) {
$entityManager = $this->getEntityManager($object);
foreach ($associations as $field => $mapping) {
if ($mapping['isOwningSide'] == false) {
if ($owningObjects = $object->{'get' . ucfirst($mapping['fieldName'])}()) {
foreach ($owningObjects as $owningObject) {
$owningObject->{'set' . ucfirst($mapping['mappedBy']) }($object);
$entityManager->persist($owningObject);
}
$entityManager->flush();
}
}
}
}
}
}
您可以直接在preUpdate函数中执行此操作
public function prePersist($societate)
{
$this->preUpdate($societate);
}
public function preUpdate($societate)
{
$conturi = $societate->getConturi();
if (count($conturi) > 0) {
foreach ($conturi as $cont) {
$cont->setSocietate($societate);
}
}
}
由于Symfony form collection的某些情况发生了变化,现在添加addChild()和removeChild(),并将by_reference选项设置为false,因此会自动保留集合,并按预期在相反的一侧设置ID 以下是完整的工作版本: addChild()方法必须包含子对象上父对象的setter:
public function addChild($child)
{
$child->setParent($this); // !important
$this->childs[] = $child;
return $this;
}
这为我完美地解决了问题,谢谢 最简单的解决方案是,自然地替换变量名;这对我很有用: “按引用”=>错误 详情如下:
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
->add('articles', EntityType::class, array(
'class' => 'EboxoneAdminBundle:Article',
'required' => false,
'by_reference' => false,
'multiple' => true,
'expanded' => false,
))
->add('formInputs', CollectionType::class, array(
'entry_type' => FormInputType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
;
}
你试过通过引用删除吗?是的,我试过了。很遗憾,没有结果。您的项目实体中有setImages、AddImages、RemoveImages和getImages方法吗?我没有setImages方法,这应该是什么样子?明白了,谢谢。这里给出了答案:这首奏鸣曲有点毛茸茸的。
prePersist()
|preUpdate()
建议对我有帮助。。但是我不得不做一些不同的事情。参见要点-也许您应该改为在setEntries
中执行foreach
?在preUpdate
中这样做似乎有些奇怪,这是最好的答案,因为它允许条令隐式地设置关系,并且将尊重非拥有方的级联定义。
public function addChild($child)
{
$child->setParent($this); // !important
$this->childs[] = $child;
return $this;
}
public function prePersist($user)
{
$this->preUpdate($user);
}
public function preUpdate($user)
{
$user->setProperties($user->getProperties());
}
protected function configureFormFields(FormMapper $formMapper)
{
$formMapper
->add('name')
->add('articles', EntityType::class, array(
'class' => 'EboxoneAdminBundle:Article',
'required' => false,
'by_reference' => false,
'multiple' => true,
'expanded' => false,
))
->add('formInputs', CollectionType::class, array(
'entry_type' => FormInputType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
))
;
}