Какой способ вставки данных один ко многим имеет отношение symfony4? - PullRequest
0 голосов
/ 19 октября 2019

Это просто, я делаю таблицу разрешений от Компаний и Пользователей, где я должен сохранить идентификатор пользователя и идентификатор компании прямо сейчас, у меня есть это, и я получаю эту ошибку

Ожидаемое значение типа "App \ Entity \ CompanyUserPermissionMap "для поля связи" App \ Entity \ User # $ companyUserPermissionMaps ", вместо этого получил" App \ Entity \ Company ".

Пользовательский объект

/**
 * @ORM\Id()
 * @ORM\GeneratedValue()
 * @ORM\Column(type="integer")
 */
private $userId;

/**
 * @ORM\Column(type="string", length=12)
 */
private $code;

/**
 * @ORM\Column(type="string", length=180, unique=true)
 */
private $email;


/**
 * @var CompanyUserPermissionMap[]
 * @ORM\OneToMany(targetEntity="App\Entity\CompanyUserPermissionMap", mappedBy="user", orphanRemoval=true)
 */
private $companyUserPermissionMaps;


public function __construct()
{
    $this->companyUserPermissionMaps = new ArrayCollection();
}


public function getCompanyUserPermissionMaps(): Collection
{
    return $this->companyUserPermissionMaps;
}

public function addCompanyUserPermissionMaps(CompanyUserPermissionMaps $permission): self
{
    if (!$this->companyUserPermissionMaps->contains($permission)) {
        $this->companyUserPermissionMaps[] = $permission;
        $permission->setUser($this);
    }

    return $this;
}

Компания

#########################
##      PROPERTIES     ##
#########################

/**
 * @ORM\Id()
 * @ORM\GeneratedValue()
 * @ORM\Column(type="integer")
 */
private $companyId;

/**
 * @ORM\Column(type="string", length=6, unique=true)
 */
private $code;



/**
 * @var CompanyUserPermissionMap[]
 * @ORM\OneToMany(targetEntity="App\Entity\CompanyUserPermissionMap", mappedBy="company", orphanRemoval=true)
 */
private $companyUserPermissionMaps;


public function __construct()
{
    $this->companyUserPermissionMaps = new ArrayCollection();

}



/**
 * @return Collection|CompanyUserPermissionMaps[]
 */
public function getCompanyUserPermissionMaps(): Collection
{
    return $this->companyUserPermissionMaps;
}

public function addCompanyUserPermissionMaps(AccountingBankPermission $permission): self
{
    if (!$this->companyUserPermissionMaps->contains($permission)) {
        $this->companyUserPermissionMaps[] = $permission;
        $permission->setAccount($this);
    }

    return $this;
}

public function removeCompanyUserPermissionMaps(AccountingBankPermission $permission): self
{
    if ($this->companyUserPermissionMaps->contains($permission)) {
        $this->companyUserPermissionMaps->removeElement($permission);
        // set the owning side to null (unless already changed)
        if ($permission->getAccount() === $this) {
            $permission->setAccount(null);
        }
    }

    return $this;
}

таблица отношений

Column(type="integer")

private $companyUserPermissionId;


/**
 * @var User
 * @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="companyUserPermissionMaps")
 * @ORM\JoinColumn(referencedColumnName="user_id", nullable=false)
 */
private $user;

/**
 * @var Company
 * @ORM\ManyToOne(targetEntity="App\Entity\Company", inversedBy="companyUserPermissionMaps")
 * @ORM\JoinColumn(referencedColumnName="company_id", nullable=true)
 */
private $company;


/**
 * @return int|null
 */
public function getCompanyUserPermissionId(): ?int
{
    return $this->companyUserPermisionId;
}



/**
 * @return User
 */
public function getUser(): ?User
{
    return $this->user;
}

/**
 * @param User $user
 * @return AccountingBankPermission
 */
public function setUser(?User $user): self
{
    $this->user = $user;
    return $this;
}

/**
 * @return Company
 */
public function getCompany(): ?Company
{
    return $this->company;
}

/**
 * @param array $company
 * @return CompanyUserPermissionMap
 */
public function setCompany(?array $company): self
{
    $this->company = $company;
    return $this;
}

Тип формы

 $builder
            ->add('roles' ,ChoiceType::class ,[
                'required'  => true,
                'choices' => $this->roles,
                'multiple' => true,
                'expanded' => true,
                'label_attr' => [
                    'class' => 'custom-control-label',
                ],
                'choice_attr' => function($val, $key, $index) {
                    return ['class' => 'custom-control-input'];
                },
                'attr'=>['class' =>'custom-checkbox custom-control']
            ])
            ->add('email', EmailType::class, [
                'label' => "E-Mail"
            ])
            ->add('firstName', TextType::class, [
                'label' => "First Name"
            ])
            ->add('lastName', TextType::class, [
                'label' => "Last Name"
            ])
            ->add('companyUserPermissionMaps' ,EntityType::class ,[
                'required' => true,
                'class'    => Company::class,
                'label'    => 'Compañia',
                'multiple' => true,
                'expanded' => false,
                'choice_label'  => 'legalName',
                'mapped'=>false
            ])
            ->add('save', SubmitType::class, [
                'label' => "Save"
            ])

и моя функция контроллера выглядит следующим образом

 $user = new User();

    $originalRoles = $this->getParameter('security.role_hierarchy.roles');

    $options=['roles' => $originalRoles ];

    $form = $this->createForm(UserType::class, $user, $options);

    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {

        $tempPassword = "some pass";

        $user->setPassword($encoder->encodePassword(
            $user,
            $tempPassword
        ));

        $companies=[];
        $companiesForm=$form->get('companyUserPermissionMaps')->getData();
        foreach ($companiesForm as $value) {
            $companies[] = $value->getCompanyId();
        }

        // Save object to database
        $entityManager = $this->getDoctrine()->getManager();

        /** @var CompanyRepository $companyRepository */
        $companyRepository = $this->getDoctrine()->getRepository(Company::class);
        $companiesArr =$companyRepository->findCompanyByArray($companies);
        $companyUserPermissionMap = new CompanyUserPermissionMap();
        $companyUserPermissionMap->setUser($user);
        $companyUserPermissionMap->setCompany($companiesArr);

        $entityManager->persist($user);
        $entityManager->persist($companyUserPermissionMap);

1 Ответ

0 голосов
/ 19 октября 2019

обновление

Хорошо, поэтому я не упомянул проблему, с которой вы на самом деле столкнулись. Компонент формы, какой бы умной она ни была, будет пытаться вызывать методы получения и установки при загрузке / изменении данных формы. Поскольку ваша форма содержит ->add('companyUserPermissionMaps',..., компонент формы вызовет getCompanyUserPermissionMaps для вашей сущности (которая вернет, вероятно, в настоящее время, вероятно, пустую коллекцию) и попытается выполнить обратную запись в сущность с помощью setCompanyUserPermissionMaps или add / * 1009. * вместо set, если они присутствуют.

Поскольку ваше поле на самом деле ведет себя так, как будто оно содержит коллекцию объектов Company, установка этих параметров на вашем объекте User, очевидно, не удастся выполнить с помощьюсообщение об ошибке:

Ожидаемое значение типа «App \ Entity \ CompanyUserPermissionMap» для поля ассоциации «App \ Entity \ User # $ companyUserPermissionMaps», вместо этого получено «App \ Entity \ Company».

, что абсолютно логично. Итак, эту проблему можно решить разными способами. Один из способов, который вы, по-видимому, уже попробовали, - установить mapped на false, но вместо false вы использовали 'false' (обратите внимание на кавычки), что оценивается как true ... по иронии судьбы. Таким образом, чтобы использовать ваш подход, вы должны удалить цитаты. Тем не менее, я предлагаю другой подход, который я бы предпочел!

конец обновления

Мой общий совет - скрывать вещи, которые вы не хотите показывать. Таким образом, в вашем конструкторе форм вместо

->add('companyUserPermissionMaps', EntityType::class, [
    'required' => true,
    'class'    => Company::class,
    'label'    => 'Compañia',
    'multiple' => true,
    'expanded' => false,
    'choice_label'  => 'legalName',
    'mapped'=>'false'
])

, который, очевидно, уже не является полем, которое обрабатывает CompanyUserPermissionMaps, а компаниями вместо этого - так что, очевидно, вы подозревали, что это семантически что-то другое, вам следует вернуться к User сущности и задайте ей функцию getCompanies вместо

public function getCompanies() {
    return array_map(function ($map) {
        return $map->getCompany();
    }, $this->getCompanyUserPermissionsMaps());
}
public function addCompany(Company $company) {
    foreach($this->companyUserPermissionMaps->toArray() as $map) {
        if($map->getCompany() === $company) {
            return;
        }
    }
    $new = new CompanyUserPermissionMap();
    $new->setCompany($company);
    $new->setUser($this);
    $this->companyUserPermissionMaps->add($new);
}
public function removeCompany(Company $company) {
    foreach($this->companyUserPermissionMaps as $map) {
        if($map->getCompany() == $company) {
            $this->companyUserPermissionMaps->removeElement($map);
        }
    }
}

, тогда вы бы назвали поле companies (т. Е. ->add('companies', ...)) и действовали бы на Company сущностях вместо этих надоедливых карт. (Мне также не очень нравится выставлять ArrayCollection и другие внутренние объекты извне. Но, эй, это ваше решение.)

однако, если ваши Карты будут содержать больше значений в какой-то момент, вы на самом делеработать с картами в вашей форме, а не только с Company сущностями.

...