Как организовать код, чтобы обернуть вокруг API систему кеша - PullRequest
0 голосов
/ 25 октября 2018

Я создаю приложение, которое использует внешний API через уже созданную библиотеку.Давайте представим, что этот внешний сервис предоставляет информацию о погоде для данного места.У нас есть такой контроллер:

class WeatherController
{
    public function show($place, WeatherLibrary $api)
    {
        return $api->getWeatherFor($place);
    }
}

Все выглядит хорошо, но у этого API есть ограничение количества запросов в минуту, что создает необходимость в системе кэширования.Я думал об использовании нативного Cache API, который предоставляет Laravel.Но, чтобы сохранить мой код организованным, я хочу, чтобы в моих контроллерах не было части логики Cache:

use Illuminate\Support\Facades\Cache;

class WeatherController
{
    public function show($place, WeatherLibrary $api)
    {
        return Cache::get($place, function() use ($place, $api) {
            $result = $api->getWeatherFor($place);
            Cache::put($place, $result, 60);
            return $result;
        });
    }
}

Какой подход я должен использовать для организации этого?Я думал о шаблоне репозитория, но я не уверен, что это правильный способ сделать это, поскольку репозитории имеют, по крайней мере, CRUD-подобные операции, и этот «репозиторий» будет иметь собственные методы в соответствии с внешней службойбизнес логика.

1 Ответ

0 голосов
/ 25 октября 2018

Исходя из комментария епископа, вы можете создать прокси-класс следующим образом:

class WeatherLibraryProxy
{
    /**
     * @var WeatherLibrary
     */
    protected $driver;

    public function __construct(WeatherLibrary $driver)
    {
        $this->driver = $driver;
    }


    /**
     * Dynamically call the underlying api driver and cache all responses
     */
    public function __call($method, $parameters)
    {
        $cache_key = $method . implode(',', $parameters);
        $minutes = 60;
        return cache()->remember($cache_key, $minutes, function () use ($method, $parameters) {
            return $this->driver->$method(...$parameters);
        });
    }

}

Затем в вашем контроллере замените введенный WeatherLibrary на ваш WeatherLibraryProxy класс:

class WeatherController
{
    public function show($place, WeatherLibraryProxy $api)
    {
        return $api->getWeatherFor($place);
    }
}

Я думаю Сервисный контейнер Laravel автоматически внедрит WeatherLibrary в конструктор вашего прокси, но если этого не произойдет, вы можете сделать что-то подобное в вашем AppServiceProvider.php:

$this->app->bind(WeatherLibraryProxy::class, function ($app) {
    return new WeatherLibraryProxy(
        $app->make(WeatherLibrary::class)
        // OR "new WeatherLibrary($arg1, $arg2, ...)", depending how it's initialized...
    );
});

который сообщает Laravel, как разрешать WeatherLibraryProxy, когда это необходимо.

Подробнее об автоматическом впрыске: https://laravel.com/docs/5.7/container#automatic-injection

Теперь любые общие функции (например, проверка оставшихся ограничений скорости) могут быть добавлены в вашПрокси-класс, который вы используете везде в своем приложении вместо базового класса WeatherLibrary.

...