Я создаю приложение, которое использует внешний 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-подобные операции, и этот «репозиторий» будет иметь собственные методы в соответствии с внешней службой бизнес логика.
Исходя из комментариев епископа, вы можете создать прокси-класс, подобный этому:
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
Теперь любые общие функции (например, проверка оставшихся ограничений скорости) можно поместить в ваш класс Proxy, который вы используете повсюду в своем приложении вместо базового класса WeatherLibrary.
Других решений пока нет …