PHPackages                             alancole/vouchers - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. alancole/vouchers

ActiveComposer[Utility &amp; Helpers](/categories/utility)

alancole/vouchers
=================

A Simple PHP library for gernating and validating voucher codes.

1.0.3(9y ago)9631910[2 issues](https://github.com/waxim/vouchers/issues)[1 PRs](https://github.com/waxim/vouchers/pulls)PHP

Since Jan 18Pushed 3y ago4 watchersCompare

[ Source](https://github.com/waxim/vouchers)[ Packagist](https://packagist.org/packages/alancole/vouchers)[ RSS](/packages/alancole-vouchers/feed)WikiDiscussions master Synced today

READMEChangelog (4)DependenciesVersions (7)Used By (0)

[![StyleCI](https://camo.githubusercontent.com/9a1f3b22f0798798bb7df73c15b8c972f43bc02b7875295378855e620eafb733/68747470733a2f2f7374796c6563692e696f2f7265706f732f37383634323736332f736869656c643f6272616e63683d6d6173746572)](https://styleci.io/repos/78642763) [![Build Status](https://camo.githubusercontent.com/541eed244226ca4eca87744356cdc299902a62d8fde7425f52749816367353cf/68747470733a2f2f7472617669732d63692e6f72672f776178696d2f766f7563686572732e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/waxim/vouchers)

Vouchers Lib
============

[](#vouchers-lib)

A PHP library for generating and validating vouchers. We make no assumptions about storage and instead offer the concept of `Bags` which can take any number of `Vouchers`. These bags can validate vouchers, generate new vouchers and apply validation rules across the whole set.

Install
-------

[](#install)

```
composer require alancole/vouchers

```

Example
-------

[](#example)

```
$model = new Vouchers\Voucher\Model([
    'owner' => [
        'required'  => true,
        'immutable' => true,
    ],
    'claimed_by' => [
        'required' => true,
    ]
]);

$collection = new Vouchers\Bag($model);
$collection->fill(1000);

$voucher = $collection->pick();

print $voucher; // FHUW-JSUJ-KSIQ-JDUI
```

Vouchers
--------

[](#vouchers)

Vouchers can take on almost any form, however you can use `Vouchers\Voucher\Model` to enforce validation and structure. The only required attribute is `code` which by default is immutable.

```
$voucher = new Vouchers\Voucher();
print $voucher; // ABCD-EFGH-IJKL
```

You may also pass an array to the voucher to set pre existing values to the voucher. Matching fields (including `code`) will be validated.

```
$voucher = new Voucher(['code' => 'ALAN-COLE-CODE', 'claimed_by' => '', 'claimed_on' => '']);
print $voucher; // "ALAN-COLE-CODE"
```

Any value passed on voucher creation can be get and set using `get()` and `set()` on the voucher.

```
$voucher->set('owner', 'Alan');
echo $voucher->get('owner'); // Alan
```

### Model

[](#model)

By creating a model you can set default values and validation on vouchers created or loaded. Models are passed as an array to `Vouchers\Voucher\Model`

```
$model = new Vouchers\Voucher\Model([
    'owner' => [
        'required'  => true,
        'immutable' => true,
    ],
    'claimed_by' => [
        'required' => true,
    ]
]);
```

If you set a voucher attribute as `immutable` then `Voucher` will throw the `ImmutableData` exception.

### Code

[](#code)

You can change the way the code is generated by settings generator on a model. A generator must implement `Vouchers\Voucher\Code\GeneratorInterface`

```
namespace My\Voucher\Generator;

use Vouchers\Voucher\Code\Interface as Generator;

class MyCode implements Generator
{
    public function part()
    {
        return bin2hex(openssl_random_pseudo_bytes(2));
    }

    public function generate()
    {
        return strtoupper(sprintf("%s-%s-%s", $this->part(), $this->part(), $this->part()));
    }

    public function validate()
    {
        return true;
    }
}
```

Then tell the model to use this generator.

```
$model = new Vouchers\Voucher\Model([
    'code' => [
        'generator' => \My\Voucher\Generator\MyCode::class
    ]
]);
```

Bags
----

[](#bags)

Bags act as collections for vouchers and allow you to enforce validations on a whole set. Bags can also act as a selector for vouchers, allowing to you pick a voucher at random and enforce rules on that selection. Bags are also `Iterable` so they can be used in loops.

```
$collection = new Vouchers\Bag();
$collection->fill(1000);

foreach($collection as $voucher) {
    print $voucher;
}
```

You can use `Vouchers\Voucher\Model` to enfore a model on all items in a bag by passing a model as the first attribute on construction.

```
$collection = new Vouchers\Bag($model);
```

You can fill a model with existing vouchers by using `add()` add will only accept an instance of `Vouchers\Voucher`

```
$vouchers = [$voucher1...$voucher100];
foreach ($vouchers as $voucher) {
    $collection->add(new Vouchers\Voucher($voucher));
}
```

You can also run a map on any array, mapping the return as new vouchers within the bag. This is handy if you need to transform data to fit a model.

```
$collection->map($vouchers, function ($voucher) {
    return new Vouchers\Voucher($voucher);
});
```

You can get a voucher by code, which can be used to see if a voucher exists.

```
$collection = new Vouchers\Bag();
$voucher = new Vouchers\Voucher(['code' => 'special-voucher']);
$collection->add($voucher);

$v = $collection->find("special-voucher");

if ($v) {
    print (string)$v;
} else {
    print "Voucher does not exist.";
}
```

### Pick

[](#pick)

You can have the bag pick you a voucher at random by using `pick()` on any bag.

```
$collection = new Vouchers\Bag();
$collection->fill(1000);

$collection->pick();
```

If you wish to validate the selection you can pass a callback to pick which will run until it returns a `true` or throw an `Vouchers\Exceptions\NoValidVouchers` exception.

```
$collection->pick(function ($voucher) {
    return (bool)$voucher->owner == "Alan";
});
```

```
try {
    $collection->pick(function ($voucher) {
        return 2 == 1;
    });
} catch (Exception $e) {
    print $e->getMessage();
}
```

You may also ask `pick()` to check all validators this bag might have (see Validate) and only return a voucher that is valid. Again this will throw `Vouchers\Exceptions\NoValidVouchers` is it doesn't find a voucher.

```
$collection->pickValid();
```

### Validate

[](#validate)

You can add validators to a bag, these validators can be used to validate requirements of a voucher using `validate()` on a bag and passing the voucher code as a parameter.

```
$collection->validate("ALAN-COLE-CODE");
```

Validators can be added as callbacks to the validator function, or as a class that implements `Vouchers\Voucher\Validator` here is an example that assumes a voucher has an `expire_date` and checks it has not passed.

```
$collection->validator(function ($voucher) {
    return $voucher->expire_date > new DateTime();
}, "Sorry, this voucher is expired");

try {
    $collection->validate("ALAN-COLE-CODE");
} catch (\Vouchers\Exceptions\VoucherNotValid $e) {
    return $e->getMessage(); // "Sorry, this voucher is expired";
}
```

### Kitchen Sink

[](#kitchen-sink)

This shows how to get vouchers from the subscriptions api, take a requested voucher, validate it and the claim it on the API.

```
$api = new Discovery\Subscriptions\Api();
$api->setApiKey(getenv("SUBS_API_KEY"));
$api->setAppId(getenv("SUBS_APP_ID"));

$vouchers = $api->getAllVouchers();

$bag = new Vouchers\Bag();
$bag->map($vouchers, function($voucher) {
    return new Vouchers\Voucher($voucher);
});

# Add some validators
$bag->validator(function ($voucher) {
    return $voucher->owner == "Eurosport";
}, "Sorry, this voucher was not valid.");

$bag->validator(function ($voucher) {
    return !$voucher->used;
}, "Sorry, this voucher has been used.");

$bag->validator(function ($voucher) {
    return new DateTime($voucher->valid_till) < new DateTime();
}, "Sorry, this voucher is expired.");

try {
    $voucher = $collection->validate(filter_val(INPUT_POST, "voucher_code", FILTER_SANITIZE_STRING));
    $voucher->set("used", true // not really needed.
    $api->putVoucherClaim($voucher); // because this takes care of it.
} catch (\Vouchers\Exceptions\VoucherNotValid $e) {
    echo $e->getMessage();
}
```

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity29

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity67

Established project with proven stability

 Bus Factor1

Top contributor holds 95.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

4

Last Release

3447d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/6cee12237f7ad937cba998c0a4745f87986389a414a529309c0ab15095801d20?d=identicon)[alancole](/maintainers/alancole)

---

Top Contributors

[![waxim](https://avatars.githubusercontent.com/u/3833567?v=4)](https://github.com/waxim "waxim (20 commits)")[![imjoehaines](https://avatars.githubusercontent.com/u/282732?v=4)](https://github.com/imjoehaines "imjoehaines (1 commits)")

---

Tags

composer-packagesecommercephpphp-libraryvoucher

### Embed Badge

![Health badge](/badges/alancole-vouchers/health.svg)

```
[![Health](https://phpackages.com/badges/alancole-vouchers/health.svg)](https://phpackages.com/packages/alancole-vouchers)
```

###  Alternatives

[workerman/gatewayclient

361282.3k30](/packages/workerman-gatewayclient)[heybigname/event-dispatcher

Event Dispatcher with a focus on Domain Events

5913.6k1](/packages/heybigname-event-dispatcher)[laravel-frontend-presets/paper

Laravel 10.x Front-end preset for paper dashboard

5018.2k](/packages/laravel-frontend-presets-paper)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
