it-source

Symfony2 엔티티 모음 - 기존 엔티티와의 연결을 추가/제거하는 방법은 무엇입니까?

criticalcode 2023. 8. 9. 20:51
반응형

Symfony2 엔티티 모음 - 기존 엔티티와의 연결을 추가/제거하는 방법은 무엇입니까?

간단한 개요

1.1 목표

제가 달성하고자 하는 것은 사용자 생성/편집 도구입니다.편집 가능한 필드는 다음과 같습니다.

  • 사용자 이름(유형: 텍스트)
  • 일반 암호(유형: 암호)
  • 전자 메일(유형: 전자 메일)
  • 그룹(유형: 집합)
  • avoRoles(유형: 컬렉션)

참고: 마지막 속성의 이름은 $role이 아닙니다. 왜냐하면 내 사용자 클래스가 FOOSerBundle의 사용자 클래스를 확장하고 있으며 역할을 덮어쓰는 것이 더 많은 문제를 일으켰기 때문입니다.그들을 피하기 위해 저는 단순히 $avoRole 아래에 제 역할 컬렉션을 저장하기로 결정했습니다.

1.2 사용자 인터페이스

템플릿은 2개의 섹션으로 구성됩니다.

  1. 사용자 양식
  2. $userRepository->모든 역할 찾기를 표시하는 표OwnOwnByUser($user) 제외

참고: 모든 역할 찾기OwnedByUser()가 사용자 지정 리포지토리 함수인 경우를 제외하고 모든 역할의 하위 집합($user에 아직 할당되지 않은 역할)을 반환합니다.

1.3 원하는 기능

1.3.1 역할 추가:


사용자가 역할 표에서 "+"(추가) 버튼을 클릭할 때그런 다음 jquery는 역할 테이블에서 해당 행을 제거합니다.AND jquery는 사용자 양식에 새 목록 항목을 추가합니다(voRoles 목록).

1.3.2 역할 제거:


사용자가 User 양식(voRoles 목록)에서 "x"(제거) 버튼을 클릭할 때그런 다음 jquery는 사용자 양식(voRoles 목록)에서 해당 목록 항목을 제거합니다.AND jquery는 역할 테이블에 새 행을 추가합니다.

1.3.3 변경사항 저장:


사용자가 "Zapisz"(저장) 버튼을 클릭할 때그런 다음 사용자 양식이 모든 필드(사용자 이름, 암호, 전자 메일, avoRole, 그룹)를 제출합니다.AND는 avoRole을 역할 엔티티의 어레이 컬렉션으로 저장합니다(다대다 관계).AND는 그룹을 역할 엔티티의 어레이 컬렉션으로 저장합니다(다대다 관계).

참고: 기존 역할 및 그룹만 사용자에게 할당할 수 있습니다.어떤 이유로든 찾을 수 없는 경우 양식의 유효성을 검사하지 않아야 합니다.


코드

이 섹션에서는 이 조치의 이면에 있는 코드에 대해 간단히 설명합니다.설명이 부족하고 코드를 봐야 한다면 말씀해주시면 붙여드릴게요.불필요한 코드로 스팸 메일을 보내는 것을 피하기 위해 처음부터 모두 붙여넣는 것은 아닙니다.

2.1 사용자 클래스

내 사용자 클래스는 FOSuserBundle 사용자 클래스를 확장합니다.

namespace Avocode\UserBundle\Entity;

use FOS\UserBundle\Entity\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use Avocode\CommonBundle\Collections\ArrayCollection;
use Symfony\Component\Validator\ExecutionContext;

/**
 * @ORM\Entity(repositoryClass="Avocode\UserBundle\Repository\UserRepository")
 * @ORM\Table(name="avo_user")
 */
class User extends BaseUser
{
    const ROLE_DEFAULT = 'ROLE_USER';
    const ROLE_SUPER_ADMIN = 'ROLE_SUPER_ADMIN';

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\generatedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToMany(targetEntity="Group")
     * @ORM\JoinTable(name="avo_user_avo_group",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
     * )
     */
    protected $groups;

    /**
     * @ORM\ManyToMany(targetEntity="Role")
     * @ORM\JoinTable(name="avo_user_avo_role",
     *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
     * )
     */
    protected $avoRoles;

    /**
     * @ORM\Column(type="datetime", name="created_at")
     */
    protected $createdAt;

    /**
     * User class constructor
     */
    public function __construct()
    {
        parent::__construct();

        $this->groups = new ArrayCollection();        
        $this->avoRoles = new ArrayCollection();
        $this->createdAt = new \DateTime();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set user roles
     * 
     * @return User
     */
    public function setAvoRoles($avoRoles)
    {
        $this->getAvoRoles()->clear();

        foreach($avoRoles as $role) {
            $this->addAvoRole($role);
        }

        return $this;
    }

    /**
     * Add avoRole
     *
     * @param Role $avoRole
     * @return User
     */
    public function addAvoRole(Role $avoRole)
    {
        if(!$this->getAvoRoles()->contains($avoRole)) {
          $this->getAvoRoles()->add($avoRole);
        }

        return $this;
    }

    /**
     * Get avoRoles
     *
     * @return ArrayCollection
     */
    public function getAvoRoles()
    {
        return $this->avoRoles;
    }

    /**
     * Set user groups
     * 
     * @return User
     */
    public function setGroups($groups)
    {
        $this->getGroups()->clear();

        foreach($groups as $group) {
            $this->addGroup($group);
        }

        return $this;
    }

    /**
     * Get groups granted to the user.
     *
     * @return Collection
     */
    public function getGroups()
    {
        return $this->groups ?: $this->groups = new ArrayCollection();
    }

    /**
     * Get user creation date
     *
     * @return DateTime
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }
}

2.2 역할 클래스

내 역할 클래스는 Symfony Security Component Core Role 클래스를 확장합니다.

namespace Avocode\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Avocode\CommonBundle\Collections\ArrayCollection;
use Symfony\Component\Security\Core\Role\Role as BaseRole;

/**
 * @ORM\Entity(repositoryClass="Avocode\UserBundle\Repository\RoleRepository")
 * @ORM\Table(name="avo_role")
 */
class Role extends BaseRole
{    
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\generatedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\Column(type="string", unique="TRUE", length=255)
     */
    protected $name;

    /**
     * @ORM\Column(type="string", length=255)
     */
    protected $module;

    /**
     * @ORM\Column(type="text")
     */
    protected $description;

    /**
     * Role class constructor
     */
    public function __construct()
    {
    }

    /**
     * Returns role name.
     * 
     * @return string
     */    
    public function __toString()
    {
        return (string) $this->getName();
    }

    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Role
     */
    public function setName($name)
    {      
        $name = strtoupper($name);
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set module
     *
     * @param string $module
     * @return Role
     */
    public function setModule($module)
    {
        $this->module = $module;

        return $this;
    }

    /**
     * Get module
     *
     * @return string 
     */
    public function getModule()
    {
        return $this->module;
    }

    /**
     * Set description
     *
     * @param text $description
     * @return Role
     */
    public function setDescription($description)
    {
        $this->description = $description;

        return $this;
    }

    /**
     * Get description
     *
     * @return text 
     */
    public function getDescription()
    {
        return $this->description;
    }
}

2.3 그룹 클래스

저는 그룹에 대한 문제가 역할에 대한 문제와 동일하기 때문에 여기서 생략합니다.제가 역할을 맡으면 그룹에서도 같은 일을 할 수 있다는 것을 압니다.

2.4 제어기

namespace Avocode\UserBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\SecurityContext;
use JMS\SecurityExtraBundle\Annotation\Secure;
use Avocode\UserBundle\Entity\User;
use Avocode\UserBundle\Form\Type\UserType;

class UserManagementController extends Controller
{
    /**
     * User create
     * @Secure(roles="ROLE_USER_ADMIN")
     */
    public function createAction(Request $request)
    {      
        $em = $this->getDoctrine()->getEntityManager();

        $user = new User();
        $form = $this->createForm(new UserType(array('password' => true)), $user);

        $roles = $em->getRepository('AvocodeUserBundle:User')
                    ->findAllRolesExceptOwned($user);
        $groups = $em->getRepository('AvocodeUserBundle:User')
                    ->findAllGroupsExceptOwned($user);

        if($request->getMethod() == 'POST' && $request->request->has('save')) {
            $form->bindRequest($request);

            if($form->isValid()) {
                /* Persist, flush and redirect */
                $em->persist($user);
                $em->flush();
                $this->setFlash('avocode_user_success', 'user.flash.user_created');
                $url = $this->container->get('router')->generate('avocode_user_show', array('id' => $user->getId()));

                return new RedirectResponse($url);
            }
        }

        return $this->render('AvocodeUserBundle:UserManagement:create.html.twig', array(
          'form' => $form->createView(),
          'user' => $user,
          'roles' => $roles,
          'groups' => $groups,
        ));
    }
}

2.5 사용자 정의 리포지토리

제대로 작동하므로 이를 게시할 필요가 없습니다. 모든 역할/그룹(사용자에게 할당되지 않은 역할/그룹)의 하위 집합을 반환합니다.

2.6 사용자 유형

사용자 유형:

namespace Avocode\UserBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class UserType extends AbstractType
{    
    private $options; 

    public function __construct(array $options = null) 
    { 
        $this->options = $options; 
    }

    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder->add('username', 'text');

        // password field should be rendered only for CREATE action
        // the same form type will be used for EDIT action
        // thats why its optional

        if($this->options['password'])
        {
          $builder->add('plainpassword', 'repeated', array(
                        'type' => 'text',
                        'options' => array(
                          'attr' => array(
                            'autocomplete' => 'off'
                          ),
                        ),
                        'first_name' => 'input',
                        'second_name' => 'confirm', 
                        'invalid_message' => 'repeated.invalid.password',
                     ));
        }

        $builder->add('email', 'email', array(
                        'trim' => true,
                     ))

        // collection_list is a custom field type
        // extending collection field type
        //
        // the only change is diffrent form name
        // (and a custom collection_list_widget)
        // 
        // in short: it's a collection field with custom form_theme
        // 
                ->add('groups', 'collection_list', array(
                        'type' => new GroupNameType(),
                        'allow_add' => true,
                        'allow_delete' => true,
                        'by_reference' => true,
                        'error_bubbling' => false,
                        'prototype' => true,
                     ))
                ->add('avoRoles', 'collection_list', array(
                        'type' => new RoleNameType(),
                        'allow_add' => true,
                        'allow_delete' => true,
                        'by_reference' => true,
                        'error_bubbling' => false,
                        'prototype' => true,
                     ));
    }

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

    public function getDefaultOptions(array $options){

        $options = array(
          'data_class' => 'Avocode\UserBundle\Entity\User',
        );

        // adding password validation if password field was rendered

        if($this->options['password'])
          $options['validation_groups'][] = 'password';

        return $options;
    }
}

2.7 역할 이름유형

이 양식은 다음을 렌더링해야 합니다.

  • 숨겨진 역할 ID
  • 역할 이름(읽기 전용)
  • 숨겨진 모듈(읽기 전용)
  • 숨겨진 설명(읽기 전용)
  • 제거(x) 버튼

모듈 및 설명은 숨겨진 필드로 렌더링됩니다. 관리자가 사용자에서 역할을 제거할 때 jQuery를 통해 역할 테이블에 해당 역할을 추가해야 하며 이 테이블에는 모듈 및 설명 열이 있습니다.

namespace Avocode\UserBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;

class RoleNameType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder            
            ->add('', 'button', array(
              'required' => false,
            ))  // custom field type rendering the "x" button

            ->add('id', 'hidden')

            ->add('name', 'label', array(
              'required' => false,
            )) // custom field type rendering <span> item instead of <input> item

            ->add('module', 'hidden', array('read_only' => true))
            ->add('description', 'hidden', array('read_only' => true))
        ;        
    }

    public function getName()
    {
        // no_label is a custom widget that renders field_row without the label

        return 'no_label';
    }

    public function getDefaultOptions(array $options){
        return array('data_class' => 'Avocode\UserBundle\Entity\Role');
    }
}

현재/알려진 문제

3.1 사례 1: 위에서 인용한 구성

위 구성에서 오류를 반환합니다.

Property "id" is not public in class "Avocode\UserBundle\Entity\Role". Maybe you should create the method "setId()"?

그러나 ID에 대한 설정자는 필요하지 않습니다.

  1. 첫 번째는 새로운 역할을 만들고 싶지 않기 때문입니다.기존의 역할과 사용자 엔티티 간의 관계를 만들고 싶습니다.
  2. 새 역할을 생성하려는 경우에도 해당 역할의 ID는 자동으로 생성되어야 합니다.

    /**

    • @ORM\Id
    • @ORM\열(유형="정수")
    • @ORM\generated Value(전략="AUTO") */ 보호된 $id;

3.2 사례 2: 역할 엔티티에 ID 속성에 대한 설정자 추가

잘못된 것 같은데, 혹시나 해서 한 거예요.이 코드를 역할 엔티티에 추가한 후:

public function setId($id)
{
    $this->id = $id;
    return $this;
}

새 사용자를 생성하고 역할을 추가하면 저장...결과는 다음과 같습니다.

  1. 새 사용자가 생성됩니다.
  2. 새 사용자에게 원하는 ID가 할당된 역할이 있습니다(yay!).
  3. 그러나 해당 역할의 이름이 빈 문자열로 덮어씁니다(bummer!)

분명히, 그것은 제가 원하는 것이 아닙니다.역할을 편집/덮어쓰기하지 않습니다.나는 단지 그들과 사용자 사이의 관계를 추가하고 싶을 뿐입니다.

3.3 사례 3: Jeppe가 제안한 해결 방법

제가 처음 이 문제를 접했을 때, Jeppe가 제안한 것과 동일한 해결책을 제시했습니다.오늘(다른 이유로) 폼/뷰를 다시 만들어야 했고 해결 방법이 작동하지 않았습니다.

Case3 User Management Controller -> createAction의 변경 사항

  // in createAction
  // instead of $user = new User
  $user = $this->updateUser($request, new User());

  //and below updateUser function


    /**
     * Creates mew iser and sets its properties
     * based on request
     * 
     * @return User Returns configured user
     */
    protected function updateUser($request, $user)
    {
        if($request->getMethod() == 'POST')
        {
          $avo_user = $request->request->get('avo_user');

          /**
           * Setting and adding/removeing groups for user
           */
          $owned_groups = (array_key_exists('groups', $avo_user)) ? $avo_user['groups'] : array();
          foreach($owned_groups as $key => $group) {
            $owned_groups[$key] = $group['id'];
          }

          if(count($owned_groups) > 0)
          {
            $em = $this->getDoctrine()->getEntityManager();
            $groups = $em->getRepository('AvocodeUserBundle:Group')->findById($owned_groups);
            $user->setGroups($groups);
          }

          /**
           * Setting and adding/removeing roles for user
           */
          $owned_roles = (array_key_exists('avoRoles', $avo_user)) ? $avo_user['avoRoles'] : array();
          foreach($owned_roles as $key => $role) {
            $owned_roles[$key] = $role['id'];
          }

          if(count($owned_roles) > 0)
          {
            $em = $this->getDoctrine()->getEntityManager();
            $roles = $em->getRepository('AvocodeUserBundle:Role')->findById($owned_roles);
            $user->setAvoRoles($roles);
          }

          /**
           * Setting other properties
           */
          $user->setUsername($avo_user['username']);
          $user->setEmail($avo_user['email']);

          if($request->request->has('generate_password'))
            $user->setPlainPassword($user->generateRandomPassword());  
        }

        return $user;
    }

불행하게도 이것은 아무것도 바꾸지 않습니다.결과는 CASE1(ID 설정자 없음) 또는 CASE2(ID 설정자 있음)입니다.

3.4 사례 4: 사용자 친화적으로 제안된 바와 같이

매핑에 캐스케이드={"cascade", "제거"}을(를) 추가하는 중입니다.

/**
 * @ORM\ManyToMany(targetEntity="Group", cascade={"persist", "remove"})
 * @ORM\JoinTable(name="avo_user_avo_group",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="group_id", referencedColumnName="id")}
 * )
 */
protected $groups;

/**
 * @ORM\ManyToMany(targetEntity="Role", cascade={"persist", "remove"})
 * @ORM\JoinTable(name="avo_user_avo_role",
 *      joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
 *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="id")}
 * )
 */
protected $avoRoles;

FormType에서 by_reference를 false로 변경하는 중:

// ...

                ->add('avoRoles', 'collection_list', array(
                        'type' => new RoleNameType(),
                        'allow_add' => true,
                        'allow_delete' => true,
                        'by_reference' => false,
                        'error_bubbling' => false,
                        'prototype' => true,
                     ));

// ...

그리고 3.3에서 제안된 해결 방법 코드를 유지하면 다음과 같은 변화가 있었습니다.

  1. 사용자와 역할 간의 연결이 생성되지 않았습니다.
  2. 그러나 역할 엔티티의 이름을 빈 문자열로 덮어씁니다(3.2에서처럼).

그래서.. 뭔가 바뀌긴 했지만 잘못된 방향으로 바뀌었군요.

버전

4.1 Symfony2 v2.0.15

4.2 독트린2 v2.1.7

4.3 FOOSer 번들 버전: 6fb81861d84d460f1d070ceb8ec180aac841f7fa

요약

저는 많은 다양한 접근법을 시도해 보았습니다(위는 가장 최근의 접근법일 뿐입니다). 그리고 코드를 공부하고 구글을 검색하고 답을 찾는 데 몇 시간을 소비한 후에는 이것이 제대로 작동하지 않았습니다.

어떤 도움이라도 주시면 대단히 감사하겠습니다.알고 싶은 것이 있으면 코드의 어떤 부분이든 게시하겠습니다.

Form 구성 요소에 문제가 있으며 이를 해결할 수 있는 쉬운 방법을 찾을 수 없다는 결론에 도달했습니다.하지만, 저는 완전히 일반적인 조금 덜 번거로운 해결책을 생각해냈습니다. 엔티티/속성에 대한 하드 코딩된 지식이 없기 때문에 발견되는 모든 컬렉션을 수정할 수 있습니다.

단순하고 일반적인 해결 방법

이렇게 하면 엔티티를 변경할 필요가 없습니다.

use Doctrine\Common\Collections\Collection;
use Symfony\Component\Form\Form;

# In your controller. Or possibly defined within a service if used in many controllers

/**
 * Ensure that any removed items collections actually get removed
 *
 * @param \Symfony\Component\Form\Form $form
 */
protected function cleanupCollections(Form $form)
{
    $children = $form->getChildren();

    foreach ($children as $childForm) {
        $data = $childForm->getData();
        if ($data instanceof Collection) {

            // Get the child form objects and compare the data of each child against the object's current collection
            $proxies = $childForm->getChildren();
            foreach ($proxies as $proxy) {
                $entity = $proxy->getData();
                if (!$data->contains($entity)) {

                    // Entity has been removed from the collection
                    // DELETE THE ENTITY HERE

                    // e.g. doctrine:
                    // $em = $this->getDoctrine()->getEntityManager();
                    // $em->remove($entity);

                }
            }
        }
    }
}

계속하기 전에 새 메서드 호출

# in your controller action...

if($request->getMethod() == 'POST') {
    $form->bindRequest($request);
    if($form->isValid()) {

        // 'Clean' all collections within the form before persisting
        $this->cleanupCollections($form);

        $em->persist($user);
        $em->flush();

        // further actions. return response...
    }
}

그래서 1년이 흘렀고, 이 질문은 꽤나 인기가 있게 되었습니다.심포니는 그 이후로 바뀌었고, 저의 기술과 지식 또한 향상되었고, 이 문제에 대한 저의 현재 접근 방식도 바뀌었습니다.

symfony2(github의 FormExtensionsBundle 프로젝트 참조)에 대한 양식 확장자 집합을 작성했으며, 이 확장자에는 One/Many-ToMany 관계를 처리하기 위한 양식 유형이 포함되어 있습니다.

이러한 문서를 작성하는 동안 수집을 처리하기 위해 컨트롤러에 사용자 지정 코드를 추가하는 것은 용납할 수 없습니다. 양식 확장자는 사용하기 쉽고, 즉시 사용할 수 있으며, 개발자의 업무를 더 어렵게 만드는 것이 아닙니다.그리고..기억하세요..건조!

그래서 저는 연관성 추가/제거 코드를 다른 곳으로 옮겨야 했습니다. 그리고 그것을 하기에 적합한 장소는 당연히 EventListener였습니다 :)

EventListener/CollectionUploadListener.php 파일을 통해 이 문제를 어떻게 처리하는지 확인하십시오.

PS. 여기서 코드를 복사할 필요가 없습니다. 가장 중요한 것은 이벤트 수신기에서 이러한 작업을 실제로 처리해야 한다는 것입니다.

해결 방법

Jepp Marianger-Lam이 제안한 해결책은 현재 제가 아는 유일한 해결책입니다.

1.1 제 경우 왜 작동을 멈췄습니까?

다른 이유로 역할 이름 유형을 다음으로 변경했습니다.

  • ID(숨김)
  • 이름(사용자 정의 유형 - 레이블)
  • 모듈 및 설명(숨김, 읽기 전용)

문제는 사용자 정의 유형 레이블 렌더링 NAME 속성입니다.


<span> 역할명 </span>

그리고 그것이 "읽기 전용"이 아니었기 때문에 POST에서 NAME을 얻을 것으로 예상되는 FORM 구성 요소.

대신 ID만 게시되었으므로 FORM 구성 요소는 NAME을 NULL로 가정합니다.

이로 인해 CASE 2 (3.2) -> 연관성을 생성하지만 ROLE NAME을 빈 문자열로 덮어씁니다.

그렇다면, 이 해결책은 정확히 무엇에 관한 것입니까?

2.1 컨트롤러

이 해결 방법은 매우 간단합니다.

컨트롤러에서 양식의 유효성을 검사하기 전에 게시된 엔티티 식별자를 가져와 일치하는 엔티티를 가져온 다음 개체로 설정해야 합니다.

// example action
public function createAction(Request $request)
{      
    $em = $this->getDoctrine()->getEntityManager();

    // the workaround code is in updateUser function
    $user = $this->updateUser($request, new User());

    $form = $this->createForm(new UserType(), $user);

    if($request->getMethod() == 'POST') {
        $form->bindRequest($request);

        if($form->isValid()) {
            /* Persist, flush and redirect */
            $em->persist($user);
            $em->flush();
            $this->setFlash('avocode_user_success', 'user.flash.user_created');
            $url = $this->container->get('router')->generate('avocode_user_show', array('id' => $user->getId()));

            return new RedirectResponse($url);
        }
    }

    return $this->render('AvocodeUserBundle:UserManagement:create.html.twig', array(
      'form' => $form->createView(),
      'user' => $user,
    ));
}

updateUser 함수의 해결 코드 아래:

protected function updateUser($request, $user)
{
    if($request->getMethod() == 'POST')
    {
      // getting POSTed values
      $avo_user = $request->request->get('avo_user');

      // if no roles are posted, then $owned_roles should be an empty array (to avoid errors)
      $owned_roles = (array_key_exists('avoRoles', $avo_user)) ? $avo_user['avoRoles'] : array();

      // foreach posted ROLE, get it's ID
      foreach($owned_roles as $key => $role) {
        $owned_roles[$key] = $role['id'];
      }

      // FIND all roles with matching ID's
      if(count($owned_roles) > 0)
      {
        $em = $this->getDoctrine()->getEntityManager();
        $roles = $em->getRepository('AvocodeUserBundle:Role')->findById($owned_roles);

        // and create association
        $user->setAvoRoles($roles);
      }

    return $user;
}

SETTER(이 경우 User.php 엔티티)가 작동하려면 다음과 같아야 합니다.

public function setAvoRoles($avoRoles)
{
    // first - clearing all associations
    // this way if entity was not found in POST
    // then association will be removed

    $this->getAvoRoles()->clear();

    // adding association only for POSTed entities
    foreach($avoRoles as $role) {
        $this->addAvoRole($role);
    }

    return $this;
}

마지막 생각

그래도, 저는 이 해결책이 다음과 같은 일을 하고 있다고 생각합니다.

$form->bindRequest($request);

해야만 합니다!잘못되었거나 Symphony의 Collection 양식 유형이 완전하지 않습니다.

Symphony 2.1에서 Form 구성 요소에 몇 가지 주요 변경 사항이 있습니다. 이 문제가 해결되기를 바랍니다.

PS. 내가 잘못한 거라면...

어떻게 해야 하는지 게시해 주세요!빠르고, 쉽고, "깨끗한" 해결책을 보게 되어 기쁩니다.

PS2. 특별한 감사:

Jeppe Marianger-Lam 및 사용자 친화적(IRC의 #symphony2에서).많은 도움이 되었습니다.건배!

이것이 제가 전에 했던 일입니다. 그것이 그것을 하는 '올바른' 방법인지는 모르겠지만, 효과가 있습니다.

, ▁after▁(▁before즉▁or▁from)▁right▁results직후▁)에서 를 얻을 때if($form->isValid()) 다음을 변수로 저장).에서 역할 목록을 물어본 다음 모든 역할을 엔티티에서 제거합니다(목록을 변수로 저장).목록을 한 후 .persist그리고.flush.

저는 방금 Symfony2 문서를 검색했습니다. 왜냐하면 저는 그것에 대해 뭔가가 생각났기 때문입니다.prototype양식 컬렉션의 경우, 그리고 이것이 나타났습니다: http://symfony.com/doc/current/cookbook/form/form_collections.html - 양식에서 javascript 컬렉션 유형의 추가 및 제거를 올바르게 처리하는 방법에 대한 예제가 있습니다.아마도 먼저 이 접근법을 시도하고, 만약 당신이 그것을 작동시킬 수 없다면 위에서 언급한 것을 나중에 시도하세요:)

더 많은 엔티티가 필요합니다.
사용자
id_user(유형: 정수)
사용자 이름(유형: 텍스트)
일반 암호(유형: 암호)
전자 메일(유형: 전자 메일)


무리
id_group(유형: 정수)
설명(유형: 텍스트)


AVOROLES
id_avorole(유형: 정수)
설명(유형: 텍스트)


*USER_Group*
id_user_group(유형: 추가)
id_user(type:user)(사용자 엔티티의 ID)
id_group(type:hostname)(그룹 엔티티의 ID)


*USER_AVOROLES*
id_user_avorole(유형: 추가)
id_user(type:user)(사용자 엔티티의 ID)
id_avorole(type:vmdk)(이것은 avorole 엔티티의 ID입니다.)


예를 들어 다음과 같은 것이 있을 수 있습니다.
사용자:
ID: 3
사용자 이름: john
일반 암호: johnpw
이메일: john@email.com


그룹:
id_group: 5
설명: 그룹 5


user_group:
id_user_group: 1
id_user: 3
id_group: 5
*이 사용자는 여러 그룹을 가질 수 있으므로 다른 행에 *

언급URL : https://stackoverflow.com/questions/11089861/symfony2-collection-of-entities-how-to-add-remove-association-with-existing-en

반응형