Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

RFE: How about caching ability? #201

Open
dicrtarasov opened this issue Feb 8, 2020 · 3 comments
Open

RFE: How about caching ability? #201

dicrtarasov opened this issue Feb 8, 2020 · 3 comments

Comments

@dicrtarasov
Copy link

dicrtarasov commented Feb 8, 2020

Curl transport provide transparent content deflating and cookies persistence. Ok, but what about caching feature. For example I use this in my project:

<?php
/**
 * @author Igor A Tarasov <develop@dicr.org>
 */

declare(strict_types = 1);

use Yii;
use yii\base\InvalidConfigException;
use yii\caching\CacheInterface;
use yii\caching\TagDependency;
use yii\di\Instance;
use yii\httpclient\Client;
use yii\httpclient\Request;
use yii\httpclient\Response;
use function is_int;

/**
 * Client with response caching.
 *
 * For caching repeatable requests, headers (Cookies, User-Agent, ...) must be similars for next requests
 *
 * @noinspection PhpUnused
 */
class CachingClient extends Client
{
    /** @var \yii\caching\CacheInterface */
    public $cache = 'cache';

    /**
     * @var bool if true, then cache key calculated with cookies. If false, then browsing is inkognito.
     * Use this only when response depends on cookies.
     */
    public $cacheCookies = false;

    /** @var int cache time, s */
    public $cacheDuration;

    /**
     * @inheritDoc
     * @throws \yii\base\InvalidConfigException
     */
    public function init()
    {
        parent::init();

        if (! empty($this->cache)) {
            $this->cache = Instance::ensure($this->cache, CacheInterface::class);
        }

        if (empty($this->cacheDuration)) {
            $this->cacheDuration = null;
        } elseif (! is_int($this->cacheDuration) || $this->cacheDuration < 0) {
            throw new InvalidConfigException('cacheDuration');
        }
    }

    /**
     * Return cache key for request.
     *
     * @param \yii\httpclient\Request $request
     * @return string[]
     */
    protected function cacheKey(Request $request)
    {
        $keyRequest = $this->cacheCookies ? $request : (clone $request)->setCookies([]);

        return [__METHOD__, $keyRequest->toString()];
    }

    /**
     * @inheritDoc
     *
     * @throws \yii\base\InvalidConfigException
     * @throws \yii\httpclient\Exception
     */
    public function send($request)
    {
        /** @var string[]|null $cacheKey key for cache */
        $cacheKey = null;

        // load from cache
        if (! empty($this->cache)) {
            $cacheKey = $this->cacheKey($request);

            // load response
            $response = $this->cache->get($cacheKey);
            if ($response instanceof Response) {
                Yii::debug('Used cached response for request: ' . $request->fullUrl, __METHOD__);

                // restore client link
                $response->client = $request->client;

                return $response;
            }
        }

        // fetch from server
        $response = parent::send($request);

        // store in cache
        if ($response->isOk && ! empty($this->cache)) {
            $cacheResponse = $this->cacheCookies ? $response : (clone $response)->setCookies([]);

            // clean connection to client to not save it in cache
            $cacheResponse->client = null;

            // save response
            $this->cache->set($cacheKey, $cacheResponse, $this->cacheDuration, new TagDependency([
                'tags' => [__CLASS__]
            ]));
        }

        return $response;
    }
}```
@dicrtarasov
Copy link
Author

Because of this issue #200
caching key from Request::toString with cookies works incorrect :(

@samdark
Copy link
Member

samdark commented Feb 8, 2020

I see that the code is practically applicable but unsure about how common it is. I'd wait for more requests of a similar feature.

@yiisoft/core-developers, @yiisoft/reviewers what do you think?

@dicrtarasov
Copy link
Author

Code updated for improvements (clean client link in Response, to not store Client in cache and restore live client before returning response).

@samdark samdark added the type:enhancement Enhancement label Feb 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants