Skip to content

Instantly share code, notes, and snippets.

@jaytaph
Last active October 3, 2019 15:17
Show Gist options
  • Star 27 You must be signed in to star a gist
  • Fork 14 You must be signed in to fork a gist
  • Save jaytaph/9640066 to your computer and use it in GitHub Desktop.
Save jaytaph/9640066 to your computer and use it in GitHub Desktop.
<?php
namespace NoxLogic\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Account
*
* @ORM\Table()
* @ORM\Entity()
*/
class Account
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity="City")
*/
protected $city;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Account
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set city
*
* @param \NoxLogic\DemoBundle\Entity\City $city
* @return Account
*/
public function setCity(\NoxLogic\DemoBundle\Entity\City $city = null)
{
$this->city = $city;
return $this;
}
/**
* Get city
*
* @return \NoxLogic\DemoBundle\Entity\City
*/
public function getCity()
{
return $this->city;
}
}
<?php
namespace NoxLogic\DemoBundle\Form\Type;
use Doctrine\ORM\EntityManager;
use NoxLogic\DemoBundle\Entity\Province;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class AccountType extends AbstractType {
protected $em;
function __construct(EntityManager $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Name of the user
$builder->add('name', 'text');
/* Add additional fields... */
$builder->add('save', 'submit');
// Add listeners
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
$builder->addEventListener(FormEvents::PRE_SUBMIT, array($this, 'onPreSubmit'));
}
protected function addElements(FormInterface $form, Province $province = null) {
// Remove the submit button, we will place this at the end of the form later
$submit = $form->get('save');
$form->remove('save');
// Add the province element
$form->add('province', 'entity', array(
'data' => $province,
'empty_value' => '-- Choose --',
'class' => 'NoxLogicDemoBundle:Province',
'mapped' => false)
);
// Cities are empty, unless we actually supplied a province
$cities = array();
if ($province) {
// Fetch the cities from specified province
$repo = $this->em->getRepository('NoxLogicDemoBundle:City');
$cities = $repo->findByProvince($province, array('name' => 'asc'));
}
// Add the city element
$form->add('city', 'entity', array(
'empty_value' => '-- Select a province first --',
'class' => 'NoxLogicDemoBundle:City',
'choices' => $cities,
));
// Add submit button again, this time, it's back at the end of the form
$form->add($submit);
}
function onPreSubmit(FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
// Note that the data is not yet hydrated into the entity.
$province = $this->em->getRepository('NoxLogicDemoBundle:Province')->find($data['province']);
$this->addElements($form, $province);
}
function onPreSetData(FormEvent $event) {
$account = $event->getData();
$form = $event->getForm();
// We might have an empty account (when we insert a new account, for instance)
$province = $account->getCity() ? $account->getCity()->getProvince() : null;
$this->addElements($form, $province);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'NoxLogic\DemoBundle\Entity\Account'
));
}
public function getName()
{
return "account_type";
}
}
<?php
namespace NoxLogic\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* City
*
* @ORM\Table()
* @ORM\Entity()
*/
class City
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @ORM\ManyToOne(targetEntity="Province", inversedBy="cities")
*/
protected $province;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return City
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set province
*
* @param \NoxLogic\DemoBundle\Entity\Province $province
* @return City
*/
public function setProvince(\NoxLogic\DemoBundle\Entity\Province $province = null)
{
$this->province = $province;
return $this;
}
/**
* Get province
*
* @return \NoxLogic\DemoBundle\Entity\Province
*/
public function getProvince()
{
return $this->province;
}
function __toString() {
return $this->getName();
}
}
<?php
namespace NoxLogic\DemoBundle\Controller;
use NoxLogic\DemoBundle\Entity\Account;
use NoxLogic\DemoBundle\Form\Type\AccountType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class DefaultController extends Controller
{
public function ajaxAction(Request $request) {
if (! $request->isXmlHttpRequest()) {
throw new NotFoundHttpException();
}
// Get the province ID
$id = $request->query->get('province_id');
$result = array();
// Return a list of cities, based on the selected province
$repo = $this->getDoctrine()->getManager()->getRepository('NoxLogicDemoBundle:City');
$cities = $repo->findByProvince($id, array('name' => 'asc'));
foreach ($cities as $city) {
$result[$city->getName()] = $city->getId();
}
return new JsonResponse($result);
}
public function createAction(Request $request)
{
$account = new Account();
// You probably want to use a service and inject it automatically. For simplicity,
// I'm just adding it to the constructor.
$form = $this->createForm(new AccountType($this->getDoctrine()->getManager()), $account);
$form->handleRequest($request);
if ($form->isValid()) {
/* Do your stuff here */
$this->getDoctrine()->getManager()->persist($account);
$this->getDoctrine()->getManager()->flush();
}
return $this->render('NoxLogicDemoBundle:Default:index.html.twig', array('form' => $form->createView()));
}
}
{# Display the form #}
{{ form(form) }}
{# Add ajax thingie that will update the city select box #}
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#account_type_province').change(function(){
var val = $(this).val();
$.ajax({
type: "POST",
url: "{{ url('province_ajax_call') }}?province_id=" + val,
success: function(data) {
// Remove current options
$('#account_type_city').html('');
$.each(data, function(k, v) {
$('#account_type_city').append('<option value="' + v + '">' + k + '</option>');
});
}
});
return false;
});
});
</script>
<?php
namespace NoxLogic\DemoBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Province
*
* @ORM\Table()
* @ORM\Entity()
*/
class Province
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity="City", mappedBy="province")
*/
protected $cities;
/**
* Constructor
*/
public function __construct()
{
$this->cities = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Province
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Add cities
*
* @param \NoxLogic\DemoBundle\Entity\City $cities
* @return Province
*/
public function addCity(\NoxLogic\DemoBundle\Entity\City $cities)
{
$this->cities[] = $cities;
return $this;
}
/**
* Remove cities
*
* @param \NoxLogic\DemoBundle\Entity\City $cities
*/
public function removeCity(\NoxLogic\DemoBundle\Entity\City $cities)
{
$this->cities->removeElement($cities);
}
/**
* Get cities
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getCities()
{
return $this->cities;
}
function __toString() {
return $this->getName();
}
}
@massil31
Copy link

Awasome solution!!!!!!!!!
Thank you for your solution, It's help me a lot!!!!!!!!

@captainwass
Copy link

Bonjour,
en fait ce formulaire fonctionne a merveille.
mais je trouve un problème lorsque je veux l'imbriquer dans un autre formulaire.
le probleme est dans cette ligne $province = $account->getCity() ? $account->getCity()->getProvince() : null; de accountType.

l'erreur est: Error: Call to a member function getCity() on a non-object

pouvez vous m'aider?

@mtchuenten
Copy link

Awesome. Thanks a million.

@MathLG
Copy link

MathLG commented Oct 20, 2016

Hello,

I'm trying to use this solution but since few days I have a persitent error:

Catchable Fatal Error: Argument 1 passed to QuizBundle\Form\AssignType::__construct() must be an instance of Doctrine\ORM\EntityManager, none given, called in D:\qcm\Dev\qcm\vendor\symfony\symfony\src\Symfony\Component\Form\FormRegistry.php on line 85 and defined

And on every forums I went they use the "__construct" function in a controller with:
$this->getDoctrine()->getEntityManager();

So I don't know what to do to fix this error after trying many things.

Can someone help me?

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment