Laragear/TokenAction

View on GitHub
src/Builder.php

Summary

Maintainability
A
35 mins
Test Coverage
<?php

namespace Laragear\TokenAction;

use Carbon\CarbonImmutable;
use Closure;
use DateTimeInterface;
use Illuminate\Support\Traits\Conditionable;
use Illuminate\Support\Traits\Tappable;
use Laragear\TokenAction\Exceptions\TokenNotFound;
use ValueError;
use function is_int;
use function value;

class Builder
{
    use Conditionable;
    use Tappable;

    /**
     * Create a new Builder instance.
     */
    public function __construct(
        protected Store $store,
        protected DateTimeInterface|int|string|null $expires = null,
        protected int $tries = 1,
        protected mixed $with = null,
        protected Closure|string|null $as = null
    )
    {
        //
    }

    /**
     * Changes the cache store to use to manage Tokens.
     *
     * @return $this
     */
    public function store(?string $store): static
    {
        $this->store->store($store);

        return $this;
    }

    /**
     * Set an amount of tries the token can be consumed.
     *
     * @return $this
     */
    public function tries(int $tries): static
    {
        $this->tries = $tries;

        if ($this->tries < 1) {
            throw new ValueError('Cannot assign less than 1 tries to a Token.');
        }

        return $this;
    }

    /**
     * Add additional payload to the token.
     *
     * @return $this
     */
    public function with(mixed $with): static
    {
        $this->with = $with;

        return $this;
    }

    /**
     * The token ID that should be used to store it, without prefix.
     *
     * @param  (\Closure():string)|string  $token
     * @return $this
     */
    public function as(Closure|string $token): static
    {
        $this->as = $token;

        return $this;
    }

    /**
     * Creates a new Token instance, optionally with a custom payload.
     */
    public function until(DateTimeInterface|int|string $expires): Token
    {
        if (is_int($expires)) {
            $expires = CarbonImmutable::now()->addMinutes($expires);
        }

        $expires = CarbonImmutable::parse($expires);

        if ($expires->isPast()) {
            throw new ValueError('Cannot make a Token already expired.');
        }

        $token = new Token($this->store, $expires, $this->generateTokenId(), $this->tries, $this->with);

        $this->store->put($token);

        return $token;
    }

    /**
     * Generate a token ID.
     */
    protected function generateTokenId(): string
    {
        if ($this->as) {
            return value($this->as);
        }

        if (isset(Token::$generator)) {
            return (Token::$generator)();
        }

        throw new ValueError('The Token ID generator is not set.');
    }

    /**
     * Retrieve and consume the token.
     */
    public function consume(string $id, int $amount = 1): ?Token
    {
        $token = $this->find($id);

        if ($token) {
            $this->store->consume($id, $amount);
        }

        return $token;
    }

    /**
     * Retrieve and consume the token, or fail if the token doesn't exist.
     */
    public function consumeOrFail(string $id, int $amount = 1): mixed
    {
        return $this->consume($id, $amount) ?? throw new TokenNotFound($id);
    }

    /**
     * Finds a token by the given ID.
     */
    public function find(string $id): ?Token
    {
        return $this->store->get($id);
    }

    /**
     * Finds a token by the given ID, or fail if the token doesn't exist.
     */
    public function findOrFail(string $id): Token
    {
        return $this->find($id) ?? throw new TokenNotFound($id);
    }

    /**
     * Delete the token by its ID.
     */
    public function destroy(string $id): void
    {
        $this->store->destroy($id);
    }
}