Symfony 形式:Country State City 三动态下拉
Symfony form: Country State City three dynamic dropdown
您好,我正在使用 Symfony 5。我需要三个动态 select 下拉菜单。这是我的实体之间的关系:国家 -> 州 -> 城市。这些链接到这样的用户实体
当我添加一个新用户时,我应该能够 select 一个国家并根据国家 selection 更新国家下拉列表;在我 select 编辑了一个州之后,城市下拉菜单也是如此。我已经按照这里的官方 Symfony 指南为国家和州工作 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", length=255)
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity=Country::class, 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', ChoiceType::class, [
'choices' => [],
'placeholder' => 'Select State',
])
->add('city', ChoiceType::class, [
'choices' => [],
])
->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']],
'required' => true,
'first_options' => ['label' => 'Password'],
'second_options' => ['label' => 'Confirm Password'],
])
->add('agreeTerms', CheckboxType::class, [
'mapped' => false,
'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', EntityType::class, [
'label' => 'state',
'placeholder' => 'Select state',
'required' => true,
'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', EntityType::class, [
'label' => 'city',
'placeholder' => 'Select city',
'required' => true,
'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', 'ASC')
;
// echo "<pre>"; print_r(($sql->getQuery()->getArrayResult())); exit;
},
'choice_label' => 'name',
'choice_value' => 'name',
'constraints' => [
new NotBlank([
'message' => 'City is required',
]),
],
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
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'),
type: $form.attr('method'),
data: data,
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>
需要更改 ajax 调用脚本。
树枝
<script>
$(document).ready(function() {
var $country = $('#registration_form_country');
var $state = $('#registration_form_state');
$country.change(function () {
var $form = $(this).closest('form');
var data = {};
data[$country.attr('name')] = $country.val();
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) {
$('#registration_form_state').replaceWith(
$(html).find('#registration_form_state')
);
$('#registration_form_city').replaceWith(
$(html).find('#registration_form_city')
);
$state = $('#registration_form_state');
$state.change( function () {
var $form = $(this).closest('form');
var data = {};
data[$state.attr('name')] = $state.val();
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) {
$('#registration_form_city').replaceWith(
$(html).find('#registration_form_city')
);
}
});
});
}
});
});
});
</script>
您好,我正在使用 Symfony 5。我需要三个动态 select 下拉菜单。这是我的实体之间的关系:国家 -> 州 -> 城市。这些链接到这样的用户实体
当我添加一个新用户时,我应该能够 select 一个国家并根据国家 selection 更新国家下拉列表;在我 select 编辑了一个州之后,城市下拉菜单也是如此。我已经按照这里的官方 Symfony 指南为国家和州工作 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", length=255)
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity=Country::class, 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', ChoiceType::class, [
'choices' => [],
'placeholder' => 'Select State',
])
->add('city', ChoiceType::class, [
'choices' => [],
])
->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']],
'required' => true,
'first_options' => ['label' => 'Password'],
'second_options' => ['label' => 'Confirm Password'],
])
->add('agreeTerms', CheckboxType::class, [
'mapped' => false,
'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', EntityType::class, [
'label' => 'state',
'placeholder' => 'Select state',
'required' => true,
'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', EntityType::class, [
'label' => 'city',
'placeholder' => 'Select city',
'required' => true,
'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', 'ASC')
;
// echo "<pre>"; print_r(($sql->getQuery()->getArrayResult())); exit;
},
'choice_label' => 'name',
'choice_value' => 'name',
'constraints' => [
new NotBlank([
'message' => 'City is required',
]),
],
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
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'),
type: $form.attr('method'),
data: data,
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>
需要更改 ajax 调用脚本。
树枝
<script>
$(document).ready(function() {
var $country = $('#registration_form_country');
var $state = $('#registration_form_state');
$country.change(function () {
var $form = $(this).closest('form');
var data = {};
data[$country.attr('name')] = $country.val();
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) {
$('#registration_form_state').replaceWith(
$(html).find('#registration_form_state')
);
$('#registration_form_city').replaceWith(
$(html).find('#registration_form_city')
);
$state = $('#registration_form_state');
$state.change( function () {
var $form = $(this).closest('form');
var data = {};
data[$state.attr('name')] = $state.val();
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) {
$('#registration_form_city').replaceWith(
$(html).find('#registration_form_city')
);
}
});
});
}
});
});
});
</script>