4

私はいくつかの調査を行いましたが、これこれ(および関連するすべての質問) を読んだ後でも、Symonfy 2 Doctrine で多対多の関係を更新する適切な方法はどれかわかりません。私がまだ見つけていない非常に簡単な方法があるはずだと感じています。

私はこの2つのエンティティを持っています:

class student_main
{
/**
* @ORM\ManyToMany(targetEntity="support_log", inversedBy="student_main")
* @ORM\JoinTable(name="support_log_student")
**/
private $support_log;

class support_log
{
/**
* @ORM\ManyToMany(targetEntity="student_main", mappedBy="support_log")
**/
private $student;

から始めたいsupport_log。コントローラーの更新アクションには、次のようなものがあります。

if ($editForm->isValid()) {        
  //add the relationship the user added
  foreach($students as $student){
    if(!$em->getRepository('mybundle:student_main')->hasSupportLog($entity,$student)){
        $entity->addstudent_main($student);//*
        }
    }
    $em->persist($entity);
    $em->flush();
    return $this->redirect($this->generateUrl('support_log_edit', array('id' => $id)));
}

もちろん、doctrine Documentation が言うように、それに応じてその関数 (addstudent_main) を変更しました:

public function addstudent_main(student_main $student)
{
    $student->addsupport_log($this); // the important addition
    $this->student[] = $student;
}

これは問題なく機能します。私の質問は、関係の削除に関するものです。フォームには複数選択があり、ユーザーはすでに関連付けられている学生とそうでない学生を選択する場合があります。それを自動的に行う方法があるはずですが、代わりに多くのコードを実行する必要がありました。

コントローラーでは、前に書いたコードの少し上に、次のように記述しました。

//delete all old relationship
foreach($idsldstudents as $idst){ //I take Id's because the doctrine collection is updating always..
            $stu=$em->getRepository('MyBundle:student_main')->find($idst);
            $stu->deletesupport_log($entity);//I had to create that method (in the entity, I do "$this->support_log->removeElement($support_log)")
            $em->persist($stu);
            $em->flush();
        }

問題のエンティティのすべての関係を削除します (もちろん、これは双方向の関係であるため、最初に反対側で削除する必要があることに注意してください)。次に、ユーザーが選択した関係が追加されます。

それを行う方法は他にもありますが、簡単な方法は見つかりませんでした。それらのすべてで、私は同じ問題を抱えています:

  • 関係が存在するかどうかを常に確認する必要があります
  • 古い関係を取得し (これは難しい)、ユーザーが示した新しい関係と比較し、それに応じて削除または作成する必要があります

これら2つの問題を自動的に処理する方法はありますか? (関係をより適切に宣言する必要があるに違いないと強く感じています-それが私が尋ねている理由です)。

前もって感謝します

編集:私のフォームには特別なものは何もありません。生成されたコードに触れていないと思います。ctrl複数選択するには、キーを使用する必要がある Symfony2 のデフォルトである、必要な複数選択が表示されます。コードは次のとおりです。

public function buildForm(FormBuilder $builder, array $options)
{
    $builder           
        ->add('student')
        ... 
        ;
}

鍵はここにかかっていますか?

4

4 に答える 4

2

ドクトリンのドキュメントによると、関連付けの所有側の変更のみをチェックします。

http://doctrine-orm.readthedocs.org/en/latest/reference/unitofwork-associations.html

したがって、最善の方法は、所有する側のエンティティの関連付けを更新し続けることです。

この場合、add メソッドと remove メソッドで、student main の support_log を削除して追加する必要があります。

class support_log
{
/**
* @ORM\ManyToMany(targetEntity="student_main", mappedBy="support_log")
**/
private $student;

public function addStudent($student) {
  $this->student[] = $student;
  $student->addSupportLog($this);
}

public function removeStudent($student) {
  $student->removeSupportLog($this);
  $this->student->removeElement($student);
}

コントローラーのアクションを変更する必要はありません。 関連付けの逆側でこれを実装することが重要です。

于 2015-03-20T21:04:59.317 に答える
2

これまでのところ、(そして永遠に答えられない質問を避けるために)、それを行うための「まだ見つけられていない簡単な方法」はないようです。コメントによると、それが私の質問に対する答えです。

しかし、最後のコメントの改善のおかげで、コードを改善してよりエレガントにすることができます。エンティティ レベルの場合: gist.github.com/3121916 (コメントから)

次に、コントローラーのコードを少し減らすことができます。

$editForm->bindRequest($request);
  if ($editForm->isValid()) { 
  //delete all old relationships, we can go from student:    
  foreach($em->getRepository('mybundle:student_main')->findAll() as $oldstudent)
  {
     $oldstudent->removeSupportLog($entity);
     //if they are related, the relationship will be deleted. 
     //(check the code from the url)  
  }  
  //add the relationship the user added in the widget
  $students=$entity->getStudent();
  foreach($students as $student) 
  {
     $entity->addstudent_main($student);
  }
  $em->persist($entity);
  $em->flush();
  return $this->redirect($this->generateUrl('support_log_edit', array('id' => $id)));
}

これはまだ私が期待していた「魔法の」symfony ソリューションではありませんが、これまでのところ、私ができる最善のことです (おそらく、このコードをリポジトリ内の関数内にグループ化して、よりエレガントにします)。

もっと良いアイデアがあれば、私はすべて耳にします。

于 2013-04-01T00:34:08.950 に答える
2

解決策を探しているすべての人に私の解決策を提示します。

Symfony 2.5 を使用しています。

私の「投稿」エンティティには、多対多の双方向があります。

コントローラ:

public function editPostAction(Post $post, Request $request)
{
    $form = $this->createForm(new NewPost(), $post, [
            'action' => $this->generateUrl('admin_edit_post', ['id' => $post->getId()])
        ]);

    $form->handleRequest($request);

    if( $form->isSubmitted() )
    {
        $this->get('post.repository')->update();
    }

    return $this->render('BlogJakonAdminPanelBundle:Post:post-edit.html.twig', array(
            'form' => $form->createView(),
            'errors' => $form->getErrors(true)
        ));
}

次のルーティングでエンティティをバインドします。

admin_edit_post:
    path:     /post/edit/{id}
    defaults: { _controller: BlogJakonAdminPanelBundle:Post:editPost }

私のリポジトリ:

public function update()
{
    try {
        $this->getEntityManager()->flush();
    } catch (\Exception $e) {
        $this->getEntityManager()->getConnection()->rollback();
        return false;
    }

    return true;
}

フォーム クラス:

class NewPost extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            [...]
            ->add('categories', 'entity', array(
                    'class' => 'BlogJakon\PostBundle\Entity\Category',
                    'property'     => 'name',
                    'multiple'     => true,
                    'expanded'     => true)
            )
            ->add(
                'save',
                'submit',
                [
                    'label' => 'Add post'
                ]
            )
            ->getForm();

    }

    public function setDefaultOption(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(
            [
                'data_class'      => 'BlogJakon\PostBundle\Entity\Post',
                'csrf_protection' => true
            ]
        );
    }

    public function getName()
    {
        return 'newPost';
    }
} 

Symfony はルーティングに id のみを追加することで特定のエンティティ (Post) を見つけることができることに注意してください。

/post/edit/{id}

于 2014-11-24T19:57:31.043 に答える