Symfony2 엔티티 콜렉션-기존 엔티티와의 연관을 추가 / 제거하는 방법은 무엇입니까?
1. 빠른 개요
1.1 목표
내가 달성하려는 것은 사용자 생성 / 편집 도구입니다. 편집 가능한 필드는 다음과 같습니다.
- 사용자 이름 (유형 : 텍스트)
- plainPassword (유형 : 비밀번호)
- 이메일 (유형 : 이메일)
- 그룹 (유형 : 컬렉션)
- avoRoles (유형 : 컬렉션)
참고 : 내 User 클래스가 FOSUserBundle의 User 클래스를 확장하고 역할을 덮어 쓰면 더 많은 문제가 발생했기 때문에 마지막 속성의 이름은 $ roles 가 아닙니다 . 이를 피하기 위해 나는 단순히 내 역할 컬렉션을 $ avoRoles 아래에 저장하기로 결정했습니다 .
1.2 사용자 인터페이스
내 템플릿 은 2 개의 섹션으로 구성됩니다.
- 사용자 양식
- $ userRepository-> findAllRolesExceptOwnedByUser ($ user);를 표시하는 테이블
참고 : findAllRolesExceptOwnedByUser ()는 사용자 정의 저장소 함수이며 모든 역할 (아직 $ user에게 할당되지 않은 역할)의 하위 집합을 반환합니다.
1.3 원하는 기능
1.3.1 역할 추가 :
언제 역할 테이블에서 사용자가 클릭 "+"(추가) 버튼을 THEN 역할 테이블에서 행 것을 JQuery와 제거합니다 및 JQuery와는 사용자 양식 (avoRoles 목록)에 새 목록 항목을 추가
1.3.2 역할 제거 :
언제 사용자 양식 (avoRoles 목록)에서 사용자가 클릭 "X"(제거) 버튼을 THEN JQuery와 제거합니다은 사용자 양식 (avoRoles 목록)에서 목록 항목 것을 및 JQuery와는 역할 테이블에 새 행을 추가합니다
1.3.3 변경 사항 저장 :
언제 사용자가 클릭 "Zapisz"버튼 (저장) THEN 사용자 양식을 제출 모든 필드 (사용자 이름, 패스워드, 이메일, avoRoles, 그룹) 과는 역할 엔티티 (ManyToMany 관계)의 ArrayCollection에로 avoRoles 저장 및 역할 개체의있는 ArrayCollection으로 그룹을 저장 ( ManyToMany 관계)
참고 : 기존 역할 및 그룹 만 사용자에게 할당 할 수 있습니다. 어떤 이유로 든 찾을 수없는 경우 양식의 유효성을 검사하지 않아야합니다.
2. 코드
이 섹션에서는이 작업 뒤에있는 코드를 제시 / 또는 간략하게 설명합니다. 설명이 충분하지 않고 코드를 확인해야하는 경우 알려 주시면 붙여 넣겠습니다. 불필요한 코드로 스팸을 보내는 것을 피하기 위해 처음부터 모든 것을 붙여 넣는 것이 아닙니다.
2.1 사용자 클래스
My User 클래스는 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 역할 클래스
My Role 클래스는 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 RoleNameType
이 양식은 다음을 렌더링해야합니다.
- 숨겨진 역할 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. 현재 / 알려진 문제
3.1 사례 1 : 위에 인용 된 구성
위 구성은 오류를 반환합니다.
Property "id" is not public in class "Avocode\UserBundle\Entity\Role". Maybe you should create the method "setId()"?
그러나 ID에 대한 setter는 필요하지 않습니다.
- 먼저 새로운 역할을 만들고 싶지 않기 때문입니다. 기존 역할 및 사용자 엔터티 간의 관계를 만들고 싶습니다.
새 역할을 생성하고 싶더라도 ID가 자동 생성되어야합니다.
/ **
- @ORM \ Id
- @ORM \ Column (유형 = "정수")
- @ORM \ generatedValue (strategy = "AUTO") * / 보호 된 $ id;
3.2 사례 2 : 역할 엔터티의 ID 속성에 대한 setter 추가
나는 그것이 틀렸다고 생각하지만 확실히하기 위해 그것을했다. 이 코드를 역할 엔티티에 추가 한 후 :
public function setId($id)
{
$this->id = $id;
return $this;
}
새 사용자를 생성하고 역할을 추가하면 저장 ... 무슨 일이 발생합니까?
- 새 사용자가 생성되었습니다.
- 새 사용자에게 원하는 ID가 할당 된 역할이 있습니다 (예!)
- 하지만 그 역할의 이름은 빈 문자열로 덮어 써집니다 .
분명히 그것은 내가 원하는 것이 아닙니다. 역할을 편집 / 덮어 쓰고 싶지 않습니다. 나는 그들과 사용자 사이에 관계를 추가하고 싶습니다.
3.3 사례 3 : Jeppe가 제안한 해결 방법
이 문제가 처음 발생했을 때 Jeppe가 제안한 것과 동일한 해결 방법을 찾았습니다. 오늘 (다른 이유로) 양식 /보기를 다시 만들어야했고 해결 방법이 작동을 멈췄습니다.
Case3 UserManagementController-> 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 setter 없음) 또는 CASE2 (ID setter 포함)입니다.
3.4 사례 4 : 사용자 친화적 인 제안
매핑에 cascade = { "persist", "remove"}를 추가합니다.
/**
* @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;
그리고 changeing by_reference을 에 거짓 FormType에서 :
// ...
->add('avoRoles', 'collection_list', array(
'type' => new RoleNameType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'error_bubbling' => false,
'prototype' => true,
));
// ...
3.3에서 제안 된 해결 방법 코드를 유지하면 뭔가 변경되었습니다.
- 사용자와 역할 간의 연결이 생성되지 않았습니다.
- ..하지만 역할 엔티티의 이름이 빈 문자열로 덮어 써졌습니다 (3.2에서와 같이).
그래서 .. 뭔가 바뀌었지만 방향이 잘못되었습니다.
4. 버전
4.1 Symfony2 v2.0.15
4.2 교리 2 v2.1.7
4.3 FOSUserBundle 버전 : 6fb81861d84d460f1d070ceb8ec180aac841f7fa
5. 요약
나는 많은 다른 접근 방식을 시도해 보았고 (위는 가장 최근의 것뿐입니다) 코드를 공부하고 Google을 사용하고 답을 찾는 데 몇 시간을 보낸 후에는이 작업을 할 수 없었습니다.
어떤 도움이라도 대단히 감사하겠습니다. 알고 싶은 것이 있으면 필요한 코드 부분을 게시하겠습니다.
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);
}
}
}
}
}
cleanupCollections()
지속하기 전에 새 메서드를 호출하십시오.
# 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 년이 지났고이 질문은 꽤 유명해졌습니다. 그 이후로 Symfony가 바뀌었고 저의 기술과 지식도 향상되었으며이 문제에 대한 현재 접근 방식도 향상되었습니다.
symfony2에 대한 양식 확장 세트를 만들었으며 ( github의 FormExtensionsBundle 프로젝트 참조 ) 여기에는 일 / 다 대대 관계를 처리 하기위한 양식 유형이 포함되어 있습니다.
이를 작성하는 동안 컬렉션을 처리하기 위해 컨트롤러에 사용자 정의 코드를 추가하는 것은 용납 할 수 없었습니다. 양식 확장은 사용하기 쉽고, 즉시 작업하며, 개발자의 삶을 더 어렵게 만드는 것이 아니라 더 쉽게 만들 수 있어야했습니다. 또 .. 기억해 .. DRY!
그래서 추가 / 제거 연관 코드를 다른 곳으로 옮겨야했고,이를 수행하기에 적합한 장소는 당연히 EventListener였습니다. :)
상기 봐 되세요 의 EventListener / CollectionUploadListener.php의 우리가 지금이 문제를 처리하는 방법을 볼 수있는 파일을.
추신. 여기에 코드를 복사하는 것은 불필요합니다. 가장 중요한 것은 그런 것들이 실제로 EventListener에서 처리되어야한다는 것입니다.
1. 해결 방법
Jeppe Marianger-Lam이 제안한 해결 방법은 현재 내가 아는 유일한 해결책입니다.
1.1 내 케이스에서 작동이 중지 된 이유는 무엇입니까?
다른 이유로 RoleNameType을 다음과 같이 변경했습니다.
- ID (숨김)
- 이름 (사용자 정의 유형-레이블)
- 모듈 및 설명 (숨김, 읽기 전용)
문제는 내 사용자 정의 유형 레이블이 NAME 속성을 다음과 같이 렌더링했습니다.
<span> 역할 이름 </ span>
그리고 "읽기 전용"이 아니기 때문에 FORM 구성 요소는 POST에서 NAME을 가져올 것으로 예상했습니다.
대신 ID 만 게시되었으므로 FORM 구성 요소는 NAME이 NULL이라고 가정합니다.
이로 인해 CASE 2 (3.2)-> 연결이 생성되지만 ROLE NAME을 빈 문자열로 덮어 씁니다.
2. 그렇다면이 해결 방법은 정확히 무엇입니까?
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;
}
3. 최종 생각
그래도이 해결 방법이
$form->bindRequest($request);
해야 할 것! 내가 뭔가 잘못했거나 심포니의 수집 양식 유형이 완전하지 않습니다.
심포니 2.1에서 제공 되는 Form 구성 요소에는 몇 가지 주요 변경 사항 이 있습니다.이 문제가 수정되기를 바랍니다.
추신. 내가 뭔가 잘못하고 있다면 ...
...해야 할 방식을 게시하십시오! 빠르고 쉽고 "깨끗한"솔루션을 보게되어 기쁩니다.
PS2. 특별히 감사함:
Jeppe Marianger-Lam 및 사용자 친화적 (IRC의 # symfony2). 당신은 매우 도움이되었습니다. 건배!
이것은 내가 전에 한 일입니다-그것이 '올바른'방법인지는 모르겠지만 작동합니다.
제출 된 양식에서 결과를 얻으면 (예 : 직전 또는 직후 if($form->isValid())
) 역할 목록을 요청한 다음 엔티티에서 모두 제거합니다 (목록을 변수로 저장). 이 목록을 사용하여 모두를 반복하고 저장소에 ID와 일치하는 역할 엔터티를 요청한 다음 사용자 엔터티 앞에 추가 persist
하고 flush
.
I just searched through the Symfony2 documentation because I remembered something about prototype
for form collections, and this turned up: http://symfony.com/doc/current/cookbook/form/form_collections.html - It has examples of how to deal correctly with javascript add and remove of collection types in forms. Perhaps try this approach first, and then try what I mentioned above afterwards if you cannot get it to work :)
You need some more entities:
USER
id_user (type: integer)
username (type: text)
plainPassword (type: password)
email (type: email)
GROUPS
id_group (type: integer)
descripcion (type: text)
AVOROLES
id_avorole (type: integer)
descripcion (type: text)
*USER_GROUP*
id_user_group (type:integer)
id_user (type:integer) (this is the id on the user entity)
id_group (type:integer) (this is the id on the group entity)
*USER_AVOROLES*
id_user_avorole (type:integer)
id_user (type:integer) (this is the id on the user entity)
id_avorole (type:integer) (this is the id on the avorole entity)
You can have for example something like this:
user:
id: 3
username: john
plainPassword: johnpw
email: john@email.com
group:
id_group: 5
descripcion: group 5
user_group:
id_user_group: 1
id_user: 3
id_group: 5
*this user can have many groups so in another row *
'IT박스' 카테고리의 다른 글
WPF DataGrid에서 데이터를 복사하여 붙여 넣을 때 OpenClipboard가 실패했습니다. (0) | 2020.11.10 |
---|---|
부동 DIV가 다른 부동 DIV의 높이와 일치하도록 어떻게 강제 할 수 있습니까? (0) | 2020.11.10 |
Thread.setPriority ()와 android.os.Process.setThreadPriority ()의 차이점은 무엇입니까? (0) | 2020.11.09 |
C # 매트릭스 라이브러리에 대한 권장 사항 (0) | 2020.11.09 |
Nodejs에서 MongoDB 데이터베이스 연결을 닫아야하는 경우 (0) | 2020.11.09 |