Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Allow to customize how invite codes are generated #44

Merged
merged 4 commits into from
Jan 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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('test@example.com'));
}

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);
}
}
Loading