Limits.php 4.11 KB
<?php
namespace App\Service;

use App\Models\Tokens;
use App\Service\Contract\HeaderLimits;
use Illuminate\Support\Facades\DB;

class Limits implements \App\Service\Contract\Limits {

    private static $_instance;
    private $token;
    private $limitCosts;

    private function __constructor(Tokens $token){
        $this->token = $token;
        $this->limitCosts = new Costs();
    }

    public static function getInstance($token): Limits
    {
        self::$_instance = new self($token);
    }

    function current(): int
    {
        return $this->token->limit;
    }

    function DayLimit(): int
    {
        $this->token->limits->first()->day;
    }

    function countObjectsLimit(\App\Service\Contract\APIRequest $request): int
    {
        $cost = $this->limitCosts->getCostObject($request);
        if ($this->limitCosts->getCostCall($request) > $this->current()){
            return 0;
        }
        return $cost > 0 ? floor(($this->current() - $this->limitCosts->getCostCall($request)) / $cost) : -1;
    }

    /**
     * @param string $service
     * @param string $method
     * @param int $limit
     * @return int
     * @throws \Exception
     * предполагается что класс работает в очереди.
     * Иначе может быть что одновременно будет два резервирования с одним и тем же остатком.
     */
    function doRezerv(\App\Service\Contract\APIRequest $request, int $objects): int
    {
        $limit = $this->getSpent($objects, $request);
        if ($this->token->limit<$limit){
            throw new \Exception('Недостаточно баллов');
        }

        DB::beginTransaction();

        try{
            $rezerv = new \App\Models\Limits();
            $rezerv->token = $this->token->id;
            $rezerv->service = $request->getService();
            $rezerv->method = $request->getMethod();
            $rezerv->spent = $limit;
            $rezerv->current = $this->token->limit;
            $rezerv->reserved = 1;
            $rezerv->save();

            $this->token->limit -= $limit;
            $this->token->save();

            DB::commit();

        }catch(\Exception $e){
            DB::rollBack();
            throw $e;
        }

        return $rezerv->id;
    }

    function removeRezerv(int $id): int
    {
        DB::beginTransaction();
        try{
            $limit = \App\Models\Limits::findOrFail($id);
            $this->token->limit += $limit->spent;
            $this->token->save();
            $limit->delete();

            DB::commit();
        }catch(\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

    function acceptRezerv($id, HeaderLimits $limits){
        DB::beginTransaction();
        try{
            $this->token->limit = $limits->getCurrentLimit();
            $this->token->save();

            $limit = \App\Models\Limits::findOrFail($id);
            $limit->spent = $limits->getSpentLimit();
            $limit->current = $limits->getCurrentLimit();
            $limit->day = $limits->getDayLimit();
            $limit->reserved = 0;
            $limit->save();

            DB::commit();
        }catch(\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

    function updateLimits(HeaderLimits $limits)
    {
        DB::beginTransaction();
        try{
            $this->token->limit = $limits->getCurrentLimit();
            $this->token->save();

            $limit = new \App\Models\Limits();
            $limit->token = $this->token->id;
            $limit->spent = $limits->getSpentLimit();
            $limit->current = $limits->getCurrentLimit();
            $limit->day = $limits->getDayLimit();
            $limit->reserved = 0;
            $limit->save();

            DB::commit();
        }catch(\Exception $e){
            DB::rollBack();
            throw $e;
        }
    }

    private function getSpent($objects, \App\Service\Contract\APIRequest $request): int
    {
        $cost = $this->limitCosts->getCostObject($request);
        return $objects * $cost + $this->limitCosts->getCostCall($request);
    }
}