Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Voting Bundle Laravel Package

kunstmaan/voting-bundle

KunstmaanVotingBundle adds reusable voting and rating features to Symfony applications, including entities, services, and templates for casting and tallying votes. Lightweight but low-maintenance; verify compatibility before use.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first. Last tag is April 2014, it targets Symfony 2.x, and it has zero dependents. Do not plan a new build on top of it — read it as a reference implementation, or fork it under your own vendor name so you control the PHP/Symfony compatibility surface.

Minimal install steps (Symfony 2.3–2.8 era):

composer require kunstmaan/voting-bundle:dev-master
// app/AppKernel.php
new Kunstmaan\VotingBundle\KunstmaanVotingBundle(),
# app/config/routing.yml
kunstmaan_voting:
    resource: "@KunstmaanVotingBundle/Resources/config/routing.yml"
    prefix:   /voting

Then app/console doctrine:schema:update --dump-sql and read the diff before you run it — the bundle ships entities, not migrations.

Where to look first, in this order:

  1. Entity/ — the vote classes (a base vote plus per-network subclasses). This tells you what a "vote" actually is: reference string, IP, timestamp, and the network-specific payload.
  2. Resources/config/ — service IDs and the routing file for the vote endpoint. Symfony 2 container IDs, so no autowiring; you'll be calling $this->get('kunstmaan_voting.…').
  3. Service/ — the class that actually registers a vote and dispatches the event. This is the only part you'll call from your own code.
  4. Controller/ — the HTTP entry point the frontend JS hits.

First use case: a campaign page where a user clicks "Like us" and you want a counted, auditable vote. Give the campaign item a stable reference string (e.g. campaign-42 or campaign-42:user-1234), let the frontend POST to the bundle's endpoint, and query the repository for the count. That's the whole value proposition: you get the ledger for free, not the UI.

Implementation Patterns

Reference strings are the primary key of your counters. Everything hangs off a free-text reference. Adopt a convention on day one — {campaign}:{item} for aggregate counts, {campaign}:{item}:{userHash} if you need per-user dedup — and never change it mid-campaign, because there's no foreign key to anything.

Register votes through the service, not the entity. Persisting a FacebookLikeVote directly skips whatever validation/expiry/event logic the service does. From your own controller:

$voteService = $this->get('kunstmaan_voting.service.vote');
// inspect Service/VoteService.php for the exact signature — it takes
// the request (for IP/session) plus a vote type and reference
$vote = $voteService->registerVote($request, $reference, 'facebook_like');

Wrap the call in try/catch: the bundle throws typed exceptions for duplicate votes, expired campaigns, and unknown vote types. Those exceptions are the API — map them to 409/410/400 responses rather than letting them 500.

Two integration styles for the frontend. Either let the bundle's controller own the route and have your JS POST to /voting/... with the CSRF token, or hide the route and call the service from your own JSON endpoint so you control auth, rate limiting, and the response shape. The second is what most production sites end up doing.

React to votes with listeners, not modifications. Find the event the service dispatches (look for EventDispatcher / VoteEvents in Service/) and subscribe to it. That's the clean extension point for sending a confirmation email, incrementing a denormalised counter, or writing to your own analytics table. It survives a fork.

Campaign deadlines: enforce twice. The bundle checks expiry at registration time. That doesn't stop a cron from continuing to send reminders or a page from rendering a live button. Keep your own Campaign entity with startsAt/endsAt and check it in your controller too.

Irregularity reporting is a query, not a feature. There's no admin UI. Build a small reporting command that groups the vote repository by IP and by reference over a time window; anything with an implausible per-IP rate is your fraud signal.

Extending vote types: subclass the base vote entity if Doctrine inheritance is configured, otherwise add a nullable column via your own entity mapping. Check DiscriminatorMap in the base entity before you assume.

Gotchas and Tips

  • It will not install on modern Symfony. Requires symfony/symfony ~2.x and PHP 5.x-era code. To use it at all today, fork it, loosen composer.json, and fix deprecated calls; don't try to composer require it into a Symfony 5/6 app.
  • No migrations. doctrine:schema:update will happily drop or rename columns on a table with production votes. Diff first, hand-write the migration.
  • Facebook Likes are client-reported. A like button callback is trivially spoofed. Treat every Facebook vote as an untrusted claim; verify against the Graph API server-side if the reward has value, or gate on your own authenticated session.
  • IP attribution breaks behind proxies. If you're on a load balancer, $request->getClientIp() is the balancer unless trusted_proxies is configured — every vote then looks like it came from one address, and your fraud report is useless.
  • No unique constraint = duplicates. Two clicks, two rows. Add a unique index on (reference, ip) or (reference, user_id) yourself if one vote per user is the rule.
  • Expiry is registration-time only. Nothing sweeps the database or flips a campaign flag on a schedule; whatever "campaign ended" means to your UI is your responsibility.
  • Container is old-style. $this->get('kunstmaan_voting.…'), no autowiring, service definitions in XML/YAML. If you fork, don't rename IDs — every site using the bundle already references them.
  • Debugging vote counts: the repository is the source of truth. Write a one-line app/console command that dumps count-by-reference before you believe a bug report; nine times out of ten the mismatch is a changed reference convention, not a lost vote.
  • Testing: instantiate the service directly with a mocked dispatcher and a fake Request, and assert on the exception types. Don't write functional tests against the bundle's controller — you'll be rewriting them the moment you take over the route.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo