如何解决Symfony 形式:Country State City 三个动态下拉菜单
您好,我使用的是 Symfony 5。我需要三个动态选择下拉列表。这是我的实体之间的关系:国家 -> 州 -> 城市。这些链接到这样的用户实体
当我添加一个新用户时,我应该能够选择一个国家并根据国家选择更新状态下拉菜单;在我选择了一个州后,城市下拉列表也是如此。我按照此处的官方 Symfony 指南为 Country 和 State 工作https://symfony.com/doc/current/form/dynamic_form_modification.html#dynamic-generation-for-submitted-forms 我应该如何管理添加第三个下拉列表?
<?PHP
namespace App\Entity;
use App\Repository\UserRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
use App\Entity\EmployeeDetails;
/**
* @ORM\Entity(repositoryClass=UserRepository::class)
* @UniqueEntity(fields={"email"},message="There is already an account with this email")
*/
class User implements UserInterface,PasswordAuthenticatedUserInterface
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\OnetoOne(targetEntity=EmployeeDetails::class,mappedBy="user_id",cascade={"persist","remove"})
*/
private $employeeDetails;
/**
* @ORM\Column(type="string",length=11)
*/
private $delete_data;
/**
* @ORM\ManyToOne(targetEntity=Country::class,inversedBy="users")
*/
private $country;
/**
* @ORM\ManyToOne(targetEntity=State::class,inversedBy="users")
*/
private $state;
/**
* @ORM\ManyToOne(targetEntity=City::class,inversedBy="users")
*/
private $city;
public function getId(): ?int
{
return $this->id;
}
public function getEmployeeDetails(): ?EmployeeDetails
{
return $this->employeeDetails;
}
public function setEmployeeDetails(?EmployeeDetails $employeeDetails): self
{
// unset the owning side of the relation if necessary
if ($employeeDetails === null && $this->employeeDetails !== null) {
$this->employeeDetails->setUserId(null);
}
// set the owning side of the relation if necessary
if ($employeeDetails !== null && $employeeDetails->getUserId() !== $this) {
$employeeDetails->setUserId($this);
}
$this->employeeDetails = $employeeDetails;
return $this;
}
public function getDeleteData(): ?string
{
return $this->delete_data;
}
public function setDeleteData(string $delete_data): self
{
$this->delete_data = $delete_data;
return $this;
}
public function getCountry(): ?Country
{
return $this->country;
}
public function setCountry(?Country $country): self
{
$this->country = $country;
return $this;
}
public function getState(): ?State
{
return $this->state;
}
public function setState(?State $state): self
{
$this->state = $state;
return $this;
}
public function getCity(): ?City
{
return $this->city;
}
public function setCity(?City $city): self
{
$this->city = $city;
return $this;
}
}
国家
<?PHP
namespace App\Entity;
use App\Repository\CountryRepository;
use App\Entity\State;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=CountryRepository::class)
*/
class Country
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string",length=255)
*/
private $name;
/**
* @ORM\OnetoMany(targetEntity=State::class,mappedBy="country")
*/
private $states;
/**
* @ORM\OnetoMany(targetEntity=City::class,mappedBy="country")
*/
private $cities;
/**
* @ORM\OnetoMany(targetEntity=User::class,mappedBy="country")
*/
private $users;
public function __construct()
{
$this->states = new ArrayCollection();
$this->cities = new ArrayCollection();
$this->users = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
/**
* @return Collection|State[]
*/
public function getStates(): Collection
{
return $this->states;
}
public function addState(State $state): self
{
if (!$this->states->contains($state)) {
$this->states[] = $state;
$state->setCountry($this);
}
return $this;
}
public function removeState(State $state): self
{
if ($this->states->removeElement($state)) {
// set the owning side to null (unless already changed)
if ($state->getCountry() === $this) {
$state->setCountry(null);
}
}
return $this;
}
/**
* @return Collection|City[]
*/
public function getCities(): Collection
{
return $this->cities;
}
public function addCity(City $city): self
{
if (!$this->cities->contains($city)) {
$this->cities[] = $city;
$city->setCountry($this);
}
return $this;
}
public function removeCity(City $city): self
{
if ($this->cities->removeElement($city)) {
// set the owning side to null (unless already changed)
if ($city->getCountry() === $this) {
$city->setCountry(null);
}
}
return $this;
}
/**
* @return Collection|User[]
*/
public function getUsers(): Collection
{
return $this->users;
}
public function addUser(User $user): self
{
if (!$this->users->contains($user)) {
$this->users[] = $user;
$user->setCountry($this);
}
return $this;
}
public function removeUser(User $user): self
{
if ($this->users->removeElement($user)) {
// set the owning side to null (unless already changed)
if ($user->getCountry() === $this) {
$user->setCountry(null);
}
}
return $this;
}
}
状态
<?PHP
namespace App\Entity;
use App\Repository\StateRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=StateRepository::class)
*/
class State
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string",length=255)
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity=Country::class,inversedBy="states")
*/
private $country;
/**
* @ORM\OnetoMany(targetEntity=City::class,mappedBy="state")
*/
private $cities;
/**
* @ORM\OnetoMany(targetEntity=User::class,mappedBy="state")
*/
private $users;
public function __construct()
{
$this->cities = new ArrayCollection();
$this->users = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getCountry(): ?Country
{
return $this->country;
}
public function setCountry(?Country $country): self
{
$this->country = $country;
return $this;
}
/**
* @return Collection|City[]
*/
public function getCities(): Collection
{
return $this->cities;
}
public function addCity(City $city): self
{
if (!$this->cities->contains($city)) {
$this->cities[] = $city;
$city->setState($this);
}
return $this;
}
public function removeCity(City $city): self
{
if ($this->cities->removeElement($city)) {
// set the owning side to null (unless already changed)
if ($city->getState() === $this) {
$city->setState(null);
}
}
return $this;
}
/**
* @return Collection|User[]
*/
public function getUsers(): Collection
{
return $this->users;
}
public function addUser(User $user): self
{
if (!$this->users->contains($user)) {
$this->users[] = $user;
$user->setState($this);
}
return $this;
}
public function removeUser(User $user): self
{
if ($this->users->removeElement($user)) {
// set the owning side to null (unless already changed)
if ($user->getState() === $this) {
$user->setState(null);
}
}
return $this;
}
}
城市
<?PHP
namespace App\Entity;
use App\Repository\CityRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass=CityRepository::class)
*/
class City
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string",inversedBy="cities")
*/
private $country;
/**
* @ORM\ManyToOne(targetEntity=State::class,inversedBy="cities")
*/
private $state;
/**
* @ORM\OnetoMany(targetEntity=User::class,mappedBy="city")
*/
private $users;
public function __construct()
{
$this->users = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getCountry(): ?Country
{
return $this->country;
}
public function setCountry(?Country $country): self
{
$this->country = $country;
return $this;
}
public function getState(): ?State
{
return $this->state;
}
public function setState(?State $state): self
{
$this->state = $state;
return $this;
}
/**
* @return Collection|User[]
*/
public function getUsers(): Collection
{
return $this->users;
}
public function addUser(User $user): self
{
if (!$this->users->contains($user)) {
$this->users[] = $user;
$user->setCity($this);
}
return $this;
}
public function removeUser(User $user): self
{
if ($this->users->removeElement($user)) {
// set the owning side to null (unless already changed)
if ($user->getCity() === $this) {
$user->setCity(null);
}
}
return $this;
}
}
表格类型
<?PHP
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Regex;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\CheckBoxType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use App\Entity\Country;
use App\Entity\State;
use App\Entity\City;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\FormInterface;
use App\Repository\CountryRepository;
use App\Repository\StateRepository;
use App\Repository\CityRepository;
use Doctrine\ORM\EntityRepository;
class RegistrationFormType extends AbstractType
{
private $countryRepository;
private $StateRepository;
private $stateCitiesRepository;
public function __construct(
CountryRepository $countryRepository,StateRepository $stateRepository,CityRepository $stateCitiesRepository
) {
$this->countryRepository = $countryRepository;
$this->countryStateRepository = $stateRepository;
$this->stateCitiesRepository = $stateCitiesRepository;
}
public function buildForm(FormBuilderInterface $builder,array $options)
{
$builder
->add('first_name')
->add('last_name')
->add('gender',ChoiceType::class,array(
'choices' => array(
'Male' => true,'Female' => false,),))
->add('dob')
->add('mobile')
->add('address',TextareaType::class)
->add('country',EntityType::class,[
'class' => Country::class,'label' => 'Country','required' => true,'choice_label' => function(Country $country) {
return $country->getName();
},'invalid_message' => 'You must select a Country','placeholder' => 'Select Country',])
->add('state',[
'choices' => [],'placeholder' => 'Select State',])
->add('city',])
->add('pincode')
->add('email')
->add('plainPassword',RepeatedType::class,[
'mapped' => false,'attr' => ['autocomplete' => 'new-password'],'constraints' => [
new NotBlank([
'message' => 'Please enter a password',]),new Length([
'min' => 6,'minMessage' => 'Your password should be at least {{ limit }} characters',// max length allowed by Symfony for security reasons
'max' => 4096,new Regex([
'pattern'=>"/^\S*(?=\S{8,})(?=\S*[a-z])(?=\S*[A-Z])(?=\S*[\d])\S*$/",'message'=>" Password must be at least 6 characters: 1 uppercase,1 lowercase,numbers,or symbols."
])
],'type' => PasswordType::class,'invalid_message' => 'The password fields must match.','options' => ['attr' => ['class' => 'password-field']],'first_options' => ['label' => 'Password'],'second_options' => ['label' => 'Confirm Password'],])
->add('agreeTerms',CheckBoxType::class,'constraints' => [
new IsTrue([
'message' => 'You should agree to our terms.',],])
->add('submit',SubmitType::class)
;
//**************** Start State Form
$addStateForm = function (FormInterface $form,$country_id) {
$form->add('state',[
'label' => 'state','placeholder' => 'Select state','class' => State::class,'query_builder' => function (StateRepository $repository) use ( $country_id ) {
return $repository->createqueryBuilder('c')
->where('c.country = :id')
->setParameter('id',$country_id)
->orderBy('c.name','ASC')
;
// echo "<pre>"; print_r(($sql->getQuery()->getArrayResult())); exit;
},'choice_label' => 'name','choice_value' => 'name','constraints' => [
new NotBlank([
'message' => 'State is required',]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,function (FormEvent $event) use ($addStateForm) {
$country = $event->getData()->getCountry();
$country_id = $country ? $country->getId() : null;
$addStateForm($event->getForm(),$country_id);
}
);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,function (FormEvent $event) use ($addStateForm) {
$data = $event->getData();
$country_id = array_key_exists('country',$data) ? $data['country'] : null;
$addStateForm($event->getForm(),$country_id);
}
);
//**************** End State Form
//**************** Start City Form
$addCityForm = function (FormInterface $form,$state_id) {
$form->add('city',[
'label' => 'city','placeholder' => 'Select city','class' => City::class,'query_builder' => function (CityRepository $repository) use ( $state_id ) {
return $repository->createqueryBuilder('c')
->where('c.state = :id')
->setParameter('id',$state_id)
->orderBy('c.name','constraints' => [
new NotBlank([
'message' => 'City is required',function (FormEvent $event) use ($addCityForm) {
$state = $event->getData()->getState();
print_r($state);
$state_id = $state ? $state->getId() : null;
$addCityForm($event->getForm(),$state_id);
}
);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,function (FormEvent $event) use ($addCityForm) {
$data = $event->getData();
$state_id = array_key_exists('state',$data) ? $data['state'] : null;
$addCityForm($event->getForm(),$state_id);
}
);
//**************** End City Form
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,]);
}
}
树枝
<script>
$(document).ready(function() {
var $country = $('#registration_form_country');
var $state = $('#registration_form_state');
// When country gets selected ...
$country.change(function () {
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data,but only include the selected country value.
var data = {};
data[$country.attr('name')] = $country.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url: $form.attr('action'),type: $form.attr('method'),data: data,success: function (html) {
// Replace current state field ...
$('#registration_form_state').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#registration_form_state')
);
}
});
});
// When state gets selected ...
$state.change( function () {
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data,but only include the selected state value.
var data = {};
data[$state.attr('name')] = $state.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url: $form.attr('action'),success: function (html) {
// Replace current city field ...
$('#registration_form_city').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#registration_form_city')
);
}
});
});
});
</script>
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。