Installation
composer require bait/poll-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Bait\PollBundle\BaitPollBundle::class => ['all' => true],
];
First Poll Form
Define a poll type in config/packages/bait_poll.yaml:
bait_poll:
poll_types:
simple:
class: Bait\PollBundle\Form\Type\SimplePollType
options:
choices: ['Option 1', 'Option 2']
Basic Usage in Controller
use Bait\PollBundle\Form\Type\SimplePollType;
public function newPollAction(Request $request)
{
$form = $this->createForm(SimplePollType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$pollData = $form->getData();
// Save to DB via Doctrine (see below)
}
return $this->render('poll/new.html.twig', ['form' => $form->createView()]);
}
Doctrine Integration
Create an entity (e.g., Poll):
// src/Entity/Poll.php
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class Poll
{
#[ORM\Id, ORM\GeneratedValue]
private ?int $id = null;
#[ORM\Column]
private string $question;
#[ORM\Column]
private array $choices;
// Getters/setters...
}
Save poll data in the controller:
$poll = new Poll();
$poll->setQuestion($pollData['question']);
$poll->setChoices($pollData['choices']);
$entityManager->persist($poll);
$entityManager->flush();
Define Poll Type
Extend AbstractPollType for custom logic:
// src/Form/Type/CustomPollType.php
use Bait\PollBundle\Form\Type\AbstractPollType;
class CustomPollType extends AbstractPollType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'choices' => ['Yes', 'No', 'Maybe'],
'allow_anonymous' => true,
]);
}
}
Register in Config
bait_poll:
poll_types:
custom:
class: App\Form\Type\CustomPollType
Render in Twig
{{ form_start(form) }}
{{ form_widget(form) }}
<button type="submit">Vote</button>
{{ form_end(form) }}
Handle Submission
public function voteAction(Request $request, Poll $poll)
{
$form = $this->createForm(CustomPollType::class, $poll);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$pollData = $form->getData();
$this->pollManager->saveVote($poll, $pollData['choice']);
}
}
Validation Use Symfony’s validation constraints in your poll type:
$builder->add('question', TextType::class, [
'constraints' => [
new NotBlank(),
new Length(['min' => 10]),
],
]);
Anonymous Votes Enable via config:
bait_poll:
poll_types:
anonymous:
class: Bait\PollBundle\Form\Type\SimplePollType
options:
allow_anonymous: true
Use AnonymousVoteListener to track votes without user association.
Results Display Query results in a controller:
$results = $entityManager->getRepository(Poll::class)
->getResults($poll->getId());
Render in Twig:
{% for choice, votes in results %}
{{ choice }}: {{ votes }} votes
{% endfor %}
Reusable Poll Components
Create a base PollManager service to handle CRUD:
// src/Service/PollManager.php
class PollManager
{
public function __construct(private EntityManagerInterface $em) {}
public function createPoll(array $data): Poll
{
$poll = new Poll();
$poll->setQuestion($data['question']);
$poll->setChoices($data['choices']);
$this->em->persist($poll);
$this->em->flush();
return $poll;
}
}
Doctrine Mismatch
Form Submission Quirks
allow_anonymous is misconfigured.form->isSubmitted() and form->isValid() separately to isolate issues.Poll Type Registration
bait_poll.yaml will throw UndefinedTypeException.bin/console debug:config bait_poll.Validation Overrides
configureOptions fully to avoid inheritance issues.Enable Debug Mode
Set APP_DEBUG=true in .env to see detailed form errors and Doctrine queries.
Log Poll Submissions
Add a PostSubmitListener to log votes:
// src/EventListener/PollListener.php
class PollListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
FormEvents::SUBMIT => 'onPollSubmit',
];
}
public function onPollSubmit(FormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
$this->logger->info('Poll submitted', ['data' => $data]);
}
}
Check Database Schema
Ensure your Poll entity matches the bundle’s expectations (e.g., choices as an array).
Custom Vote Storage
Extend Vote entity to add metadata (e.g., IP, timestamp):
#[ORM\Entity]
class Vote
{
#[ORM\Column]
private string $ipAddress;
#[ORM\Column]
private \DateTimeInterface $votedAt;
}
Event-Driven Workflows Listen for poll events (once implemented) to trigger actions:
// Example (hypothetical future event)
PollEvents::VOTE_SUBMITTED => 'onVoteSubmitted',
CLI Poll Creation Until the command-line utility is added, create a custom command:
bin/console make:command CreatePoll
// src/Command/CreatePollCommand.php
class CreatePollCommand extends Command
{
protected function configure(): void
{
$this->setName('app:create-poll')
->addArgument('question', InputArgument::REQUIRED)
->addArgument('choices', InputArgument::IS_ARRAY);
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$pollData = [
'question' => $input->getArgument('question'),
'choices' => $input->getArgument('choices'),
];
$this->pollManager->createPoll($pollData);
$output->writeln('Poll created!');
return Command::SUCCESS;
}
}
Poll Type Inheritance
Child poll types inherit parent options unless explicitly overridden in configureOptions.
Anonymous Votes
allow_anonymous: true, votes are stored without user association.Vote entity mapping.Choice Format
The bundle expects choices as an array of strings. For complex options (e.g., objects), override the form type’s buildForm method.
Batch Processing For high-traffic polls, use Doctrine batch inserts:
$em->getConnection()->beginTransaction();
$conn->executeStatement('INSERT INTO votes (...) VALUES (...)', $params);
$em->getConnection()->commit();
Caching Results Cache poll results with
How can I help you explore Laravel packages today?