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

Coupon Code Laravel Package

atelierdisko/coupon_code

Atelierdisko's coupon_code package helps Laravel applications generate, validate, and redeem coupon codes. It supports configurable code formats, usage limits, expiry dates, and redemption tracking, offering a clean, extensible API for adding promotional codes to your Eloquent models.

Deep Wiki
Context7

Getting Started

The package is intentionally small: it generates and validates coupon code strings. Treat it as a string utility, not a full coupon system — it has no concept of redemption, expiry, or persistence. Look first at the CouponCode class (the generator) and CouponCodeValidator (the rules), then check the README for the exact method names in the version you're installing.

Minimal steps:

  1. Install via Composer: composer require atelierdisko/coupon_code
  2. Confirm the autoloaded namespace classes using composer show atelierdisko/coupon_code and glance at vendor/atelierdisko/coupon_code/src/.
  3. Generate a code:
use Atelierdisko\CouponCode\CouponCode;

$code = new CouponCode();
echo $code->generate(); // e.g. "A7K3-9MXP"
  1. Validate a code you already hold:
$validator = new CouponCodeValidator();
$validator->isValid($_POST['coupon']);

First realistic use case: generating a batch of codes at checkout-promo creation time, and validating a user-submitted string before you hand it to your own domain logic. Since the library is stateless, wire it into a Laravel service or action class rather than a controller inline — you'll want to swap the generator for tests.

Implementation Patterns

Bind the generator behind an interface. Wrap it in your own CouponGenerator contract so you can stub it in tests and change the underlying library later:

// app/Services/CouponCodeGenerator.php
interface CouponCodeGenerator
{
    public function generate(): string;
    public function validate(string $code): bool;
}

// app/Services/LibraryCouponCodeGenerator.php
class LibraryCouponCodeGenerator implements CouponCodeGenerator
{
    public function __construct(
        private CouponCode $generator,
        private CouponCodeValidator $validator,
    ) {}

    public function generate(): string
    {
        return $this->generator->generate();
    }

    public function validate(string $code): bool
    {
        return $this->validator->isValid($code);
    }
}

Register the binding in a CouponServiceProvider (or AppServiceProvider).

Batch generation at creation time. Generate codes once, persist them, and validate against your own database afterward. Validation via the library is a cheap format check, not a uniqueness guarantee:

$codes = collect(range(1, 500))->map(fn () => $this->generator->generate());

// Persist with unique constraint, retry on collision
DB::transaction(function () use ($codes) {
    Coupon::insert($codes->map(fn ($code) => [
        'code' => $code,
        'created_at' => now(),
        'updated_at' => now(),
    ])->all());
});

Two-stage validation. Use the library first (format/shape), then your own DB check (existence, single-use, expiry, amount). This short-circuits garbage input before touching the database:

public function redeem(string $rawCode, User $user): CouponRedemption
{
    $code = strtoupper(trim($rawCode));

    if (! $this->codes->validate($code)) {
        throw ValidationException::withMessages(['coupon' => 'Invalid coupon format.']);
    }

    return DB::transaction(function () use ($code, $user) {
        $coupon = Coupon::where('code', $code)->lockForUpdate()->first();

        if (! $coupon || $coupon->redeemed_at) {
            throw ValidationException::withMessages(['coupon' => 'Coupon not found or already used.']);
        }

        // mark redeemed, apply discount, etc.
    });
}

Form request validation. Add a custom rule that delegates to the generator's validator:

class CouponRule implements ValidationRule
{
    public function __construct(private CouponCodeGenerator $codes) {}

    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (! is_string($value) || ! $this->codes->validate($value)) {
            $fail('The :attribute is not a valid coupon code.');
        }
    }
}

Config quirks. The library typically exposes configuration (length, allowed character set, grouping/separator) via its constructor or setters. Pin these values in config/coupons.php and resolve them through your service provider, so the format is controlled in one place — not scattered through controllers.

Gotchas and Tips

  • Case sensitivity is on you. Normalize (uppercase, trim) before storing and before validating. Codes generated with mixed case will bite you when users type them from a receipt.
  • Library validation ≠ authenticity. Anyone can construct a string that passes format validation. Always require a DB lookup before applying a discount. The library is a shape checker.
  • Uniqueness isn't guaranteed. Small code spaces and large batches invite collisions. Use a UNIQUE constraint on the code column and handle the exception (retry with a fresh generation), rather than trusting the library.
  • Ambiguous characters. Many coupon generators exclude characters like 0/O and 1/I for OCR/typing safety. Check whether this package does — if not, consider a custom generator or post-processing.
  • Not a Laravel package. No service provider, no facade, no published config. Register bindings yourself in AppServiceProvider. Any config lives in your own config/coupons.php.
  • Testability. Because the generator is non-deterministic, unit tests should not assert exact codes. Assert format via regex, or bind a deterministic fake generator/validator in your test container. Use $this->mock(CouponCodeGenerator::class) rather than trying to predict the random output.
  • Version pinning. The repo is small with irregular releases. Pin a specific version in composer.json and add a regex-based integration test asserting your expected format, so an upgrade that changes character set or separator fails loudly.
  • Extension points are limited. If you need prefixes (user ID, campaign), suffixes, or checksum validation, wrap the generator in your own class rather than modifying the library. This keeps upgrades painless.
  • Logging redemption failures. Log the raw submitted code and normalized form separately — invaluable for debugging user reports like "my code doesn't work." Never log the user's full form submission.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
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