Skip to content

Commit

Permalink
Allow to customize how invite codes are generated (#44)
Browse files Browse the repository at this point in the history
* Allow to customize how invite codes are generated

* Remove unrelated feature

* Fix docblocks

* wip
  • Loading branch information
mateusjunges authored Jan 28, 2024
1 parent 7a71ecf commit b54a2a9
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 13 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ If you think this package helped you in any way, you can sponsor me on GitHub!
- [Create multiple invite codes](#create-multiple-invite-codes)
- [Redeeming invite codes](#redeeming-invite-codes)
- [Redeeming invite codes without dispatching events](#redeeming-invite-codes-without-dispatching-events)
- [Customizing how invite codes are generated](#customizing-how-invite-codes-are-generated)
- [Extending the `Invite` model](#extending-the-invite-model)
- [Handling invite codes exceptions](#handling-invite-codes-exceptions)
- [Using artisan commands](#using-artisan-commands)
- [Tests](#tests)
Expand Down Expand Up @@ -228,6 +230,22 @@ you can use the `withoutEvents()` method:
\Junges\InviteCodes\Facades\InviteCodes::withoutEvents()->redeem('YOUR-INVITE-CODE');
```

# Customizing how invite codes are generated
By default, this package generates a random 16 characters string that. Sometimes, you may want to customize how your invitation code is generated,
for adding a prefix to the invitation code or anything you need.

If you need to customize how your invite codes are generated, you can add a call to the InviteCodes facade `createInviteCodesusing` method, in your service provider:

```php
\Junges\InviteCodes\Facades\InviteCodes::createInviteCodeUsing(static function () {
return 'THIS-IS-MY-INVITE-'.\Illuminate\Support\Str::random();
});
```

From now on, all of your invites will have the `THIS-IS-MY-INVITE-` prefix.

Also, the package itself will handle duplicate invites, so you don't need to take care of that yourself.

# Extending the `Invite` model
The `\Junges\InviteCodes\Models\Invite` is fully extendable and replaceable. You can extend or create a new model to be used instead of the default one,
and the only thing you need to do is implement the `\Junges\InviteCodes\Contracts\InviteContract` interface, which contains some required methods for this package to work.
Expand Down
22 changes: 11 additions & 11 deletions src/Facades/InviteCodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,23 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Facade;
use Junges\InviteCodes\Contracts\InviteCodesFactory;
use Junges\InviteCodes\Contracts\InviteContract;
use Junges\InviteCodes\Models\Invite;

/**
* Class Factory.
*
* @method static $this withoutEvents() Will dispatch no events.
* @method static $this redeem(string $code) Redeem an invite code.
* @method static $this create() Create an invite code.
* @method static $this maxUsages(int $usages = null) Set the max allowed usages for invite codes.
* @method static $this restrictUsageTo(string $email) Set the user who can use the invite code.
* @method static $this expiresAt($date) Set the invite code expiration date.
* @method static $this expiresIn(int $days) Set the invite code expiration date to $days from now.
* @method static InviteCodesFactory withoutEvents() Will dispatch no events.
* @method static InviteContract redeem(string $code) Redeem an invite code.
* @method static InviteCodesFactory create() Create an invite code.
* @method static InviteCodesFactory maxUsages(int $usages = null) Set the max allowed usages for invite codes.
* @method static InviteCodesFactory restrictUsageTo(string $email) Set the user who can use the invite code.
* @method static InviteCodesFactory expiresAt($date) Set the invite code expiration date.
* @method static InviteCodesFactory expiresIn(int $days) Set the invite code expiration date to $days from now.
* @method static Invite save() Save the invite code.
* @method static Collection make(int $quantity) Save $quantity invite codes.
* @method static Collection<int, InviteContract> make(int $quantity) Save $quantity invite codes.
* @method static void macro($name, $macro)
* @method static bool hasMacro($name)
* @method static $this canBeUsedOnce()
* @method static void createInviteCodeUsing(?callable $callable = null)
* @method static InviteCodesFactory canBeUsedOnce()
*/
class InviteCodes extends Facade
{
Expand Down
19 changes: 17 additions & 2 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ class Factory implements InviteCodesFactory
protected ?string $to = null;
protected ?CarbonInterface $expires_at;
protected bool $dispatch_events = true;
protected static ?\Closure $createInviteCodeUsing = null;

public static function createInviteCodeUsing(callable $callable = null): void
{
self::$createInviteCodeUsing = $callable !== null ? $callable(...) : null;
}

/** If used, no events will be dispatched. */
public function withoutEvents(): self
Expand All @@ -54,7 +60,7 @@ public function redeem(string $code): Invite
$model = app(config('invite-codes.models.invite_model', Invite::class));

/** @var Invite|null $invite */
$invite = $model->where('code', Str::upper($code))->first();
$invite = $model->where('code', $code)->first();

if (! $invite instanceof InviteContract || ! $this->inviteCanBeRedeemed($invite)) {
throw new InvalidInviteCodeException('Your invite code is invalid');
Expand Down Expand Up @@ -139,7 +145,7 @@ public function save(): Invite
$model = app(config('invite-codes.models.invite_model', Invite::class));

do {
$code = Str::upper(Str::random(16));
$code = $this->createInvitationCode();
} while ($model->where('code', $code)->first() instanceof $model);

return $model->create([
Expand Down Expand Up @@ -209,4 +215,13 @@ private function shouldDispatchEvents(): bool
{
return $this->dispatch_events;
}

private function createInvitationCode(): string
{
if (self::$createInviteCodeUsing instanceof \Closure) {
return call_user_func(self::$createInviteCodeUsing);
}

return Str::upper(Str::random(16));
}
}
15 changes: 15 additions & 0 deletions tests/FactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
namespace Junges\InviteCodes\Tests;

use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Junges\InviteCodes\Contracts\InviteContract;
use Junges\InviteCodes\Events\InviteRedeemedEvent;
use Junges\InviteCodes\Facades\InviteCodes;
use Junges\InviteCodes\Models\Invite;

class FactoryTest extends TestCase
{
Expand Down Expand Up @@ -42,4 +44,17 @@ public function test_macro(): void
$this->assertInstanceOf(InviteContract::class, $invite);
$this->assertTrue($invite->usageRestrictedToEmail('[email protected]'));
}

public function test_it_can_customize_how_invite_code_is_created(): void
{
InviteCodes::createInviteCodeUsing(static function () {
return 'PREFIX-12345';
});

$invite = InviteCodes::create()->save();

$this->assertSame('PREFIX-12345', $invite->code);

InviteCodes::createInviteCodeUsing(null);
}
}

0 comments on commit b54a2a9

Please sign in to comment.