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

Laravel Survey Laravel Package

matt-daneshvar/laravel-survey

Laravel Survey helps you build and manage surveys in Laravel. Create questionnaires with multiple question types, collect and store user responses, and use included models, migrations, and validation for a simple survey API.

View on GitHub
Deep Wiki
Context7

Getting Started

This release (v0.6.0) is a maintenance drop: the only change is widened framework constraints for Laravel 13.x. There are no API, schema, or config changes, so if you are on Laravel 10–12 nothing you have written will break — composer update matt-daneshvar/laravel-survey is safe. The only reason to treat it as a deliberate upgrade step is if you pin illuminate/* or orchestra/testbench versions and need the widened constraint to resolve.

First steps for a new install:

  1. composer require matt-daneshvar/laravel-survey
  2. Publish the package assets — you generally want both the config and the migrations, because the config holds the model class map and the migrations hold the actual tables:
    php artisan vendor:publish --provider="MattDaneshvar\Survey\SurveyServiceProvider"
    php artisan migrate
    
  3. Add the package traits to your User (or any answerable model):
    • one trait exposes survey ownership ($user->surveys()),
    • the other exposes participation ($user->answeredSurveys() / answers). Read the README for the exact trait names in your installed version — they have been renamed across releases.
  4. Build your first survey in a seeder or tinker, not in a controller. A survey is just a record with questions(), and each question carries content, type, options, and a rules array.

The fastest first use case is a single-page feedback form (NPS + free text): create one survey with two questions, render them in a Blade loop, validate using each question's rules, then persist answers. That exercises the whole package — schema, validation, persistence — in about 40 lines.

Implementation Patterns

Define surveys as code, not clicks. Keep a SurveyDefinitions class or a seeder that is idempotent (firstOrCreate on the survey name, updateOrCreate on a stable question key). Surveys are content that needs to exist in dev, staging, and prod, and rebuilding them by hand is the single biggest source of "works on my machine" pain with this package.

Drive validation from the question's rules column. The package stores validation rules as a JSON array per question, so the canonical pattern is to build a rules array keyed by question id:

$rules = $survey->questions->mapWithKeys(fn ($q) => ["answers.{$q->id}" => $q->rules ?? []]);

$data = validator($request->all(), $rules)->validate();

This keeps validation next to the question definition instead of duplicated in a FormRequest. For radio/select questions, append Rule::in($question->options) — the stored rules rarely include the option whitelist, and without it a client can post any string.

One Blade partial per question type. type is a free-form string (text, textarea, radio, select, number…). The package does not ship views, so you own rendering. Map type to resources/views/surveys/questions/{type}.blade.php with a @includeIf fallback — this is the cleanest extension point and it stops you writing a switch in three places.

Wrap submission in a transaction. Creating a submission plus N answers is multi-row; a half-saved submission will poison your reporting queries. Wrap it and pair it with an idempotency guard (unique index on survey_id + user_id, or a client-supplied submission UUID) so a double-click does not create two entries.

Use the traits for scoping and authorization. $user->surveys() gives you ownership; back it with a policy ($this->authorize('view', $survey)) and a can:answer,survey middleware so you never leak a survey by id. For teams, add a team_id to the published surveys migration and a global scope — the package has no tenancy concept of its own.

Reporting is plain Eloquent. Answers join back to questions, so aggregation is Answer::where('question_id', $q->id)->selectRaw('content, count(*) as total')->groupBy('content')->get() for choice questions, and avg() over a numeric question for ratings. Build one SurveyReport class rather than scattering these queries across controllers; you will reuse them for exports and dashboards.

Headless/API usage works fine — expose questions as an API resource, accept answers as {question_id: value}, and let the same validation map run server-side.

Gotchas and Tips

  • Publishing migrations makes you the owner. The config lets you swap model classes, but if you later change survey_model the foreign keys in your published tables still point at the old table names. Decide the model map once, before you publish.
  • Config cache. php artisan config:cache after editing the model map, or your swapped classes silently do nothing in production while working locally.
  • Custom models must implement the package contracts, not just extend Model. Extending the shipped model is the safe route; implementing the interface from scratch usually breaks relation assumptions.
  • rules is JSON, not a string. A question saved with "required|max:255" instead of ["required","max:255"] will blow up in the validator. Always write arrays in seeders.
  • Empty rules mean the field is optional but still present in the payload. If you build the rules array with mapWithKeys, a question with null rules becomes an empty array — harmless — but do not use array_filter on the rules map, or optional questions that were answered will bypass validation entirely.
  • Watch the cascade on delete. Check the published migration's onDelete for answers. Deleting a survey in production is a data-loss operation; add a soft-delete or an archival flag to surveys rather than relying on the package default.
  • Options storage is version-sensitive. Some releases store options as a JSON column on questions, others as a relation. Dump $question->toArray() first before writing your form partial — do not assume.
  • Ordering. Questions come back in insertion order in most setups, but if you reorder them in an admin UI add an explicit order column and ->orderBy('order'); relying on id will drift as soon as you edit a survey.
  • Testing. Use RefreshDatabase plus the package factories, and assert on the stored answer rows rather than the HTTP response — that catches validation-map mistakes that a 302 redirect hides.
  • Debugging tip: Survey::with('questions')->first()->toArray() gives you the full shape (types, options, rules) in one call, which is far faster than reading the migrations when a form field renders wrong.
  • Upgrade hygiene: v0.6.0 only touches framework constraints, so after upgrading run composer why-not matt-daneshvar/laravel-survey if resolution fails — the conflict will be your own pinned illuminate/support, not this package.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin