Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9111807
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 17, 20262026-06-17T03:35:23+00:00 2026-06-17T03:35:23+00:00

So I’ve spent around 5 or 6 hours today battling with Symfony2 forms and

  • 0

So I’ve spent around 5 or 6 hours today battling with Symfony2 forms and am at the point where I’d like some advice from other members of the community. I’ve tried over 3 different methods to achieve what I’m after and had no success. I’ve read through the docs, googled everything, asked others, and I’m only a little bit better off than when I started.

My use case

I’m building a system where you can order tickets. But the core problem is how to design the order part of the system.

  • a Ticket has a name, and start and end dates where it’s available (other stuff as well but lets keep the example simple.
  • an Order may have multiple Tickets selected and for each Ticket there is a quantity.
  • an Order has a Customer. This part is fine and works dandy!

After reading around and trying different things, I gathered that to represent the Order’s Ticket and quantity, I needed another entity OrderTicket corresponds to an OrderItem from https://github.com/beberlei/AcmePizzaBundle and the Pizza is my Ticket.

  • an OrderTicket has a Ticket and quantity.

On my order page where an order is created, I want the following:

  • a form for Customer details – name, email, address. This part works fine.
  • a form for the Tickets. I want the Ticket name displayed, in a textbox or even a string; not in a select box (which is what is happening now). I want the quantity to be specified next to the ticket name. If there’s no quantity set, this means that ticket is not selected.
  • the Tickets should be filtered where they are available depending on todays date – this is achieved elsewhere (in the backend admin where they’re created) by using a custom repository method on a form type with a query builder closure.

My back end

The Order/OrderTicket/Ticket design is largely based on https://github.com/beberlei/AcmePizzaBundle

Ticket

/**
 * @ORM\Entity(repositoryClass="Foo\BackendBundle\Entity\TicketsRepository")
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="tickets")
 */
class Tickets
{
    // id fields and others
    
    /**
     * @Assert\NotBlank
     * @ORM\Column(type="string", nullable=true)
     */
    protected $name;

    /**
     * @ORM\Column(type="date", name="available_from", nullable=true)
     */    
    protected $availableFrom;

    /**
     * @ORM\Column(type="date", name="available_to", nullable=true)
     */    
    protected $availableTo;
}

OrderTicket

/**
 * @ORM\Table()
 * @ORM\Entity
 */
class OrderTicket
{
    // id field

    /**
     * @ORM\Column(name="quantity", type="integer")
     */
    private $quantity;

    /**
     * @ORM\ManyToOne(targetEntity="Tickets")
     */
    protected $ticket;

    /**
     * @ORM\ManyToOne(targetEntity="Orders", inversedBy="tickets")
     */
    protected $order;
    
    // getters and setters for quantity, ticket and order
}

Order

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="orders")
 */
class Orders
{   
    // id field and other stuff
    
    /**
     * @ORM\OneToMany(targetEntity="OrderTicket", mappedBy="order", cascade={"persist"})
     **/
    protected $tickets;

    /**
     * @ORM\ManyToOne(targetEntity="Customer", cascade={"persist"})
     */
    protected $customer;

    public function __construct()
    {
        $this->tickets = new \Doctrine\Common\Collections\ArrayCollection();
    }
    
    // getters, setters, add for Tickets and Customer
}

Customer

/**
 * @ORM\Table()
 * @ORM\Entity
 */
class Customer
{
    // id, name, email, address fields

}

This creates a schema like so (table naming differences are from auto generation):

CREATE TABLE `tickets` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `available_from` date DEFAULT NULL,
  `available_to` date DEFAULT NULL,
  PRIMARY KEY (`id`)
);
CREATE TABLE `Customer` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `address` longtext COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
);
CREATE TABLE `OrderTicket` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `ticket_id` int(11) DEFAULT NULL,
  `order_id` int(11) DEFAULT NULL,
  `quantity` int(11) NOT NULL,
  PRIMARY KEY (`id`)
);
CREATE TABLE `orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `customer_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

Forms

class CustomerType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('email')
            ->add('name')
            ->add('address')
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Foo\BackendBundle\Entity\Customer'
        ));
    }

    public function getName()
    {
        return 'foo_backendbundle_customertype';
    }
}

class OrderTicketType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('quantity', 'integer')
            ->add('ticket')
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Foo\BackendBundle\Entity\OrderTicket'
        ));
    }

    public function getName()
    {
        return 'foo_backendbundle_ordertickettype';
    }
}

class OrdersType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('customer', new CustomerType())
            ->add('tickets', 'collection', array(
                'type' => new OrderTicketType(),
                'allow_add'    => true,
                'allow_delete' => true,
                'prototype'    => true,
            ))
        ;
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Foo\BackendBundle\Entity\Orders',
        ));
    }

    public function getName()
    {
        return 'foo_backendbundle_orderstype';
    }
}

The form

<form action="{{ path('index') }}" method="post" {{ form_enctype(form) }}>
    <h3>Tickets</h3>

    {{ form_errors(form) }}

    <table>
        <thead>
            <tr>
                <td>Ticket</td>
                <td>Quantity</td>
        </thead>
        <tbody>
            {% for ticketrow in form.tickets %}
            <tr>
                <td>{{ form_widget(ticketrow.ticket) }}</td>
                <td>{{ form_widget(ticketrow.quantity) }}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

    <h3>Customer</h3>

    {% for customer in form.customer %}
        {{ form_row(customer) }}
    {% endfor %}
</form>

And finally the controller

class DefaultController extends Controller
{
    /**
     * @Route("/", name="index")
     * @Template()
     */
    public function indexAction(Request $request)
    {
        $em = $this->getDoctrine()->getManager();
        // IMPORTANT - the Tickets are prefiltered for active Tickets, these have to be injected into the Order atm. In other places I use this method on the query builder
        $tickets = $em->getRepository('FooBackendBundle:Tickets')->findActive();

        // check no tickets

        $order = new Orders();

        // To prepopulate the order with the available tickets, we have to do it like this, due to it being a collection,
        // rather than using the forms query_builder like everywhere else
        foreach($tickets as $ticket) {
            $ot = new OrderTicket();
            $ot->setTicket($ticket);
            $ot->setQuantity(0);
            $ot->setOrder($order);
            $order->addTicket($ot);
        }

        $form = $this->createForm(new OrdersType(), $order);

        if ($request->isMethod('POST')) {

            $form->bind($request);
            
            // IMPORTANT here I have to remove the previously added Tickets where the quantity is 0 - as they're not wanted in the Order.  Is there a better way to do this?
            // if the quantity of Ticket is 0, do not add to order
            // note we use the validation callback in Order to check total quantity of OrderTickets is > 0
            $order->removeTicketsWithNoQuantity();

            if ($form->isValid()) {
            
                $em->persist($order);
                $em->flush();

                return $this->redirect($this->generateUrl('order_show', array('id' => $order->getId())));
            }
        }

        return array('form' => $form->createView());
    }
}

Summary

This works and will save the Order correctly, but I’m not sure it is the correct way to do what I want, and it does not display as I want.

You can see below in the images how it looks and how the Order goes through. It is worth noting that in each of the Ticket drop downs is the rest of the Tickets but which are not active.

The Order page:

order1

The Order summary page after save:

order2

The 3 Tickets displayed are the ones that have been filtered, and I only want these Tickets on the form. I ONLY WANT TO SEE THE TICKET NAME, NOT AN EDITABLE DROP DOWN.

The core problem is that they are presented as editable drop downs. I may just want a text string of the Ticket name, or maybe even the Ticket price in the future. I’m not sure how to achieve this. I know that the ticket field and relationship must be rendered somehow so that it can be bound in the controller. So basically I want to be able to use the Ticket entity and it’s fields on the same row as the quantity text box.

So let’s step out of the crapstorm of Symfony2’s forms and put this in perspective – in the normal world, obviously I’d just retrieve the Tickets, then for each Ticket, I’d print the Ticket name, any other stuff I wanted, a hidden Ticket id, then an input for the Ticket quantity. Back into SF2 a little – I guess I need the Ticket entity available whilst looping the OrderTicket collection.

Please help me!

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-17T03:35:25+00:00Added an answer on June 17, 2026 at 3:35 am

    The easiest solution based on your code above would be create a custom type for your Ticket entity that simply displays the current ticket as a label, and also create a data transformer for it.

    namespace WineVision\BackendBundle\Form\Type;
    
    use Symfony\Component\Form\AbstractType;
    use Doctrine\Common\Persistence\ObjectManager;
    use Symfony\Component\Form\FormBuilderInterface;
    
    use WineVision\BackendBundle\Form\Transformer\TicketToIdTransformer;
    
    class TicketLabelType extends AbstractType
    {
        private $om;
    
        public function __construct(ObjectManager $om)
        {
            $this->om = $om;
        }
    
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $transformer = new TicketToIdTransformer($this->om);
            $builder->addViewTransformer($transformer);
        }    
    
        public function getParent()
        {
            return 'hidden';
        }
    
        public function getName()
        {
            return 'ticket_label_type';
        }    
    }
    

    Then create a widget in Resources/Form/fields.html.twig

    {% block ticket_label_type_widget %}
        {% spaceless %}
        <input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} />
        <span class="ticketName">{{ form.vars.data.ticketNameMethod }}</span>
        {% endspaceless %}
    {% endblock %}
    

    TicketToIdTransformer:

    namespace WineVision\BackendBundle\Form\Transformer;
    
    use Symfony\Component\Form\DataTransformerInterface;
    use Symfony\Component\Form\Exception\UnexpectedTypeException;
    
    use Doctrine\Common\Persistence\ObjectManager;
    
    class TicketToIdTransformer implements DataTransformerInterface
    {
        private $om;
    
        public function __construct(ObjectManager $om)
        {
            $this->om = $om;
        }
    
        public function transform($ticket)
        {
            if (null === $ticket) {
                return "";
            }
    
            if (!$ticket instanceof \WineVision\BackendBundle\Entity\Ticket) {
                throw new UnexpectedTypeException($ticket, '\WineVision\BackendBundle\Entity\Ticket');
            }
    
    
            return $ticket->getId();
        }
    
        public function reverseTransform($id)
        {
    
            if ('' === $id || null === $id) {
                return null;
            }
    
            return $this->om
                        ->getRepository('WineVisionBackendBundle:Ticket')
                        ->findOneBy(array('id' => $id));
    
        }
    }
    

    Then create the service for your TicketType and pass the doctrine.orm.entity_manager as an argument, and in your OrderTicketType, use

    $builder->add('ticket', 'ticket_label_type');
    

    That should solve your problem for the code you’ve given above. To further extend the solution, you shouldn’t pre-populate each order with each ticket type, and instead create a a custom collectiontype that uses Form Events to populate the collection with all of the ticket fields.

    Hope this helps! I apologize if there are any syntax errors here. I’ve copied the code from one of my applications, and modified it for your needs.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

For some reason, after submitting a string like this Jack’s Spindle from a text
I have a string like this: La Torre Eiffel paragonata all&#8217;Everest What PHP function
link Im having trouble converting the html entites into html characters, (&# 8217;) i
I have just tried to save a simple *.rtf file with some websites and
I've got a string that has curly quotes in it. I'd like to replace
I am trying to render a haml file in a javascript response like so:
I would like to run a str_replace or preg_replace which looks for certain words
I'm parsing an RSS feed that has an &#8217; in it. SimpleXML turns this
I know there's a lot of other questions out there that deal with this
I have a text area in my form which accepts all possible characters from

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.