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

Voucher Laravel Package

3neti/voucher

3neti/voucher is a Laravel/PHP package for generating, managing, and redeeming vouchers. It provides voucher code handling, validation, and Eloquent-friendly integration, making it easier to add promotional, discount, or redemption workflows to your application.

View on GitHub
Deep Wiki
Context7

Getting Started

This package models voucher contracts as data — validation requirements (signature, selfie, OTP, face match, time window, location) are represented as *InstructionData DTOs that you attach to a voucher definition. Start by reading the ValidationInstructionData class first: it is the aggregator that tells you which DTO types exist and how they are composed, so it doubles as the map of the whole validation engine.

Minimal first use case — build a voucher contract with a time-bound, location-gated requirement:

use YourPackage\Data\TimeValidationInstructionData;
use YourPackage\Data\LocationValidationInstructionData;
use YourPackage\Data\ValidationInstructionData;

$instructions = new ValidationInstructionData(
    time: new TimeValidationInstructionData(
        startsAt: now()->addHour(),
        endsAt: now()->addHours(3),
    ),
    location: new LocationValidationInstructionData(
        latitude: 14.5995,
        longitude: 120.9842,
        radiusMeters: 150,
    ),
);

Two things to note on day one:

  • Use the *InstructionData names, not the legacy ones. As of 0.10.3 the canonical DTOs are TimeValidationInstructionData and LocationValidationInstructionData, matching the pre-existing SignatureValidationInstructionData, SelfieValidationInstructionData, OtpValidationInstructionData, and FaceMatchValidationInstructionData. The old TimeValidationData / LocationValidationData classes still exist but are deprecated shims.
  • Check constructor signatures before assuming. This release is a rename only; the underlying properties and constructor parameters are unchanged, so migrating is a class-name swap and nothing more.

Implementation Patterns

Construct ValidationInstructionData from the canonical DTOs. The aggregator was updated in 0.10.3 to use the new names internally, so you can rely on instanceof TimeValidationInstructionData checks and on ::class comparisons throughout your own code without the shim layer getting in the way.

Type-hint against the new classes, not the old ones. Any factory, form request, action, or service that produces a time or location instruction should declare the *InstructionData type. This keeps static analysis and IDE navigation clean and means you are never depending on a class that is explicitly marked for removal.

final class BuildVoucherContract
{
    public function handle(array $payload): ValidationInstructionData
    {
        return new ValidationInstructionData(
            signature: ! empty($payload['signature'])
                ? new SignatureValidationInstructionData(...)
                : null,
            time: isset($payload['starts_at'])
                ? TimeValidationInstructionData::from($payload)
                : null,
        );
    }
}

Normalise at the boundary. Because both old and new class names resolve to compatible objects (the shims extend the canonical DTOs), a mixed codebase will still run. The clean pattern is to convert once — in a mapper or form request — and pass only canonical DTOs deeper into the domain. That way any legacy TimeValidationData arriving from a third-party integration or an older queued job is upgraded in a single, testable place.

Test against the contract, not the class name. Assertions like assertInstanceOf(TimeValidationInstructionData::class, $instruction) pass for both the canonical class and the shim, which is exactly what you want while integrations catch up. Reserve strict assertSame(TimeValidationInstructionData::class, $instruction::class) for tests that specifically guard the deprecation migration.

Serialize with care if you persist contracts. If you store voucher contracts as JSON and hydrate via ::from(), the payload keys are unaffected by this release, but be deliberate about which class you hydrate into — hydrating into the deprecated shim will silently keep deprecated code paths alive in your application.

Gotchas and Tips

  • Deprecation shims are a one-way door. TimeValidationData extends TimeValidationInstructionData means the old name is a subclass, not an alias. A method that type-hints TimeValidationData will reject a TimeValidationInstructionData instance — the covariance does not work in reverse. Audit for any type hints or instanceof checks using the old names; these are the only places the rename can actually break you.
  • instanceof TimeValidationData is now narrower than you think. Since the canonical class does not extend the shim, code branching on the legacy class will quietly skip the new DTOs. Grep for the old class names as part of the upgrade, even though the release is marked non-breaking.
  • "No breaking changes" applies to the public contract, not to your imports. The release notes guarantee existing integrations run unmodified; they do not guarantee that static analysers, PHPStan baselines, or IDE inspection profiles stay quiet. Expect new deprecation notices and update suppressions deliberately rather than globally.
  • Constructor arguments are unchanged, so an automated rename is safe. A project-wide find-and-replace of TimeValidationData → TimeValidationInstructionData and LocationValidationData → LocationValidationInstructionData across use statements and type hints is a low-risk migration — but do it in a branch, and re-run your contract tests, because a naive replace will also rewrite the deprecated class definitions if the package source is vendored into your repo.
  • Extension points inherit the naming convention. If you have written your own instruction DTOs, follow the *InstructionData suffix now that the full set is consistent: the aggregator and any reflection-based discovery are keyed on that convention, and mixing suffixes is how you end up with instructions that validate but are never dispatched.
  • Log the class name when debugging validation. With six instruction types and two names in circulation, the fastest diagnosis for "why did this voucher fail/pass" is to log $instruction::class alongside the result — you will immediately see whether a legacy shim is still in the path.
  • Pin the version. If your integration depends on the shims existing, add an upper bound below the release that removes them; the notes say retained, not permanent.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle