GithubHelp home page GithubHelp logo

renoki-co / laravel-eloquent-query-cache Goto Github PK

View Code? Open in Web Editor NEW
1.0K 18.0 84.0 223 KB

Adding cache on your Laravel Eloquent queries' results is now a breeze.

License: Apache License 2.0

PHP 99.22% Blade 0.78%
laravel eloquent query cache redis query-builder laravel-eloquent-queries invalidation cache-storage database

laravel-eloquent-query-cache's People

Contributors

advil0 avatar deepdiver1975 avatar dependabot-preview[bot] avatar dependabot[bot] avatar devajmeireles avatar giannicic avatar jampire avatar laravel-shift avatar rennokki avatar s-shiryaev avatar shinsenter avatar squatto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-eloquent-query-cache's Issues

inner join statements not cached !

Hi, and thanks for the great works!
I have an issue with inner join statements are not cached example:
while mostly think the issue because the pluck method not added to model methods!

select "discount" from "products" inner join "category_product" on "products"."id" = "category_product"."product_id" where "category_product"."category_id" = 29 and "active" = 1 and exists (select * from "categories" where "products"."category_id" = "categories"."id") order by "category_product"."order" asc

while Products Model are cached, category_product model cached and categories model cached!
statement example

  $Products =  new  \App\Category ;
            $Products = $Products->newQuery();
            $Products = $Products->find($cat->id)->ProductsN()->has("Mcat")->with('Mcat');
            $DiscountIds =  $Products->pluck("discount")->toArray();

any ideas ?

thanks in advance

Handle cache saving depending on environment

Hi!

First of all, this package has saved my project! Haha.

I want know if we have some method to control the cache saving based on environment. For i.e:

  • I dont want save the cache if I'm on development environment.

I solved this problem like this:
image

... but the cache file still generated (but not used in next query)!

It would be interesting if we could do:
$query->dontCache(true/false);

So we could use the conditional of the environment variable

[ Suggestion ] Flush Many-to-Many Relationships Table

Hello,

I was testing the package and everything works absolutely fine when caching models.

For example if I have a Model with a many-to-many relation, and I update that relation, the cache won't flush and update, even if I use protected static $flushCacheOnUpdate = true;.

I was thinking that those relation could have a separated model and define protected static $flushCacheOnUpdate = true; there, but IMO isn't really dinamic.

I don't have the skills to build this feature so, I will leave here the suggestion. Don't really know if it's easy to have an array of relation to flush cache on attach, detach, sync or simply like protected static $flushRelationsCacheOnUpdate = true;

STEPS TO REPRODUCE

  1. have a model like Template
  2. have a model like Site
  3. have a table for a many-to-many relationship between the models
  4. on model Template and Site, configure the caching with public $cacheFor = 86400; and protected static $flushCacheOnUpdate = true;
  5. on a basic controller query the Template for id 1 (eg.)
  6. after that do $template->sites()->attach(1)
  7. after, remove attach and reload the page
  8. query again the Template::find(1) and dd($template)'
  9. You should see the relation came empty

Stay safe!

Thanks,
Helder

setting for cacheFor as function AND varibale

is it possible to set the time to cache in form of function and variable

    /**
     * Specify the amount of time to cache queries.
     * Do not specify or set it to null to disable caching.
     *
     * @var int|\DateTime
     */
    public $cacheFor = 3600;

    /**
     * Specify the amount of time to cache queries.
     * Set it to null to disable caching.
     *
     * @return mixed
     */
    public function cacheFor()
    {
        if (request()->user()->hasRole('admin')) {
            return null;
        }

        return 1337;
    }

that way, we can conditionally handle the cache which helps with

  • settings across environments
  • some User (admins) always bypass the cache

flushCacheOnUpdate - SoftDelete doesn't work

Hello, I encountered a new problem.
Example
EcommerceOffer::where("id", $id)->delete(); -- deleted_at = '2021-06-10 17:00:00' updated ?
QueryCacheable > FlushQueryCacheObserver > deleted
SoftDelete not triggering either.

cache queries to specific table

Hi,

As expected I am not a technical person. The purpose that I am chasing is to cache all queries in the form of DB::(TABLE)->where('XXX','YYY')->get()->toArray() or similarly DB::(TABLE)->whereRaw('XXX','YYY')->get()->toArray(). The cache should invalidate on update/create/delete. Please can you kindly guide on steps?

Boot method inside QueryCacheable trait is clashing and overriding other traits boot method

I'm getting an error when booting my model (App\Product). The error is the following:

Undefined index: App\Product
On laravel/framework/src/Illuminate/Database/Eloquent/Model.php:

protected function initializeTraits()
{
    foreach (static::$traitInitializers[static::class] as $method) {
        $this->{$method}();
    }
}

I think the right approach is to change the boot method on the QueryCacheable trait to use the recommended Laravel approach for booting traits. So instead of being public static function boot() it would be public static function bootQueryCacheable() and also remove the call to parent::boot()

Concrete Explanation about Cache Tags

First of all I would like to say that this package solves a very big problem for me.

Now I would like to know about cacheTags. I'll explain in detail, I don't know if I didn't understand or if it's not working properly.

I have the getThroughId method, and in it I set the cache tag to: 'announcement:id_1', for example. However when I parse the cache via Redis-cli, I see that this "tag" is empty, and the cache has really gone somewhere else, something like:
"laravel_database_laravel_cache:d8480f04bdab8f0a2bfe7798e478abff705048d8:leqc:2ae5775e226f5a09747f7d249952285ce8b9cb4c68f35a43000a2f6d291ee053"

Images:

The tag that I want
image

The value on it:
image
EMPTY!

But analyzing another one with a bigger name:
image
The contet is there!

So I would like to know why when I call cacheTags it doesn't insert the content into it, but into another index?

Not caching when pluck is used without using get first

Hello,

thank you for this wonderful project :). Something I noticed:

Category::whereName('Foobar')->firstOrFail()->values()->get()->pluck('name', 'id')->all();

Cached. get() retrieves all values first. Then specific columns are retrieved.

Category::whereName('Foobar')->firstOrFail()->values()->pluck('name', 'id')->all();

Not cached. A query is constructed such that not all columns are returned but only those that are specified in pluck.

I would expect the second (better) query to be cached. Is this a limitation of this project?

Code completion - @method in trait

Add phpDoc to trait, for enable autocompletion:

/**
 * @method Builder cacheFor(int $seconds)
 * @method Builder cacheTags(string[] $tags)
 * @method Builder cachePrefix(string $prefix)
 * @method Builder cacheDriver(string $driver)
 */
trait QueryCacheable {}

Suggest: Delete cache with Wildcard

Caching
$model->cacheTags(['Tags.id.name'])

Delete cache like this:
$model->flushQueryCache(['Tags.*'])

Or like :
$model->tags('Tags')->flush()

Does this work with *Eloquent* builder...?

This looks like a great package...something I can benefit from. However, I'm trying to use it with a model where I have my own custom Eloquent builder.

Please look at the following link: https://timacdonald.me/dedicated-eloquent-model-query-builders/

The builder extends Illuminate\Database\Eloquent\Builder rather than Illuminate\Database\Query\Builder.

Am I doing something wrong, or does this not support Illuminate\Database\Eloquent\Builder...?

Thanks...! ๐Ÿค“

This doesn't seem to be working on Local

I'm using laravel debugbar which was showing me some queries taking about 2 seconds.

I added caching to the model as described in the docs but debugbar is still telling me the query is taking about 2 seconds.

Have I missed something?

Caching query builder

Is it possible to cache query builder? like for example:

DB::cacheFor(60 * 60)->select("SELECT DISTINCT ".$field." FROM ".$schemaName.".tests")

thanks!

On update, only flush the updated model from the cache - not all of them

Hi,

Is it possible to just flush the "updated" model from the cache, instead of all models (of the same type)?

IE: If I have a model "Foo" and I query from the DB id 1 and id 2, then a subsequent query for id 1 or id 2 should result in the data come from the cache. However, if I update id 1, and have have $flushCacheOnUpdate=TRUE set, then both id 1 and id 2 are flushed from the cache.

I would like just id 1 to be flushed, so that the next query for that ID retrieves the data from the DB (with the updates).

flushQueryCache method not found

I have an Account model, and it implements Rennokki\QueryCache\Traits\QueryCacheable.
Current version 2.4.2

I am calling Account::flushQueryCache(); to flush the cache.

My IDE mentions the method is not found, and the cache is not being cleared in tests. I did not find the method in QueryCacheable either.
What am I missing :)

[feature] jenssegers/laravel-mongodb support

I'm using https://github.com/jenssegers/laravel-mongodb to have Eloquent queries for MongoDB, is there a way to use this caching with that library?

My following the basic set up I get

Call to a member function prepare() on null

at

Illuminate\Database\Connection::Illuminate\Database\{closure}
vendor/laravel/framework/src/Illuminate/Database/Connection.php:331
...

$statement = $this->prepared(
                $this->getPdoForSelect($useReadPdo)->prepare($query)
)
            

Issues with string params

Hi, firstly let me say I love the package. It Has saved a great deal of time improving efficiency within our app.

While implementing this within my setup I've noticed a couple of issues.

The public function get($columns = ['*']) and public function selectSub($query, $as) methods implemented in Rennokki\QueryCache\Query\Builder handle parameters differently to \Illuminate\Database\Eloquent\Builder

public function get($columns = ['*'])

The method should be able to accept a single column as a string and then wrap this using the Arr::wrap helper as declared in \Illuminate\Database\Eloquent\Builder::get.

When the model does not need caching this is fine as the parent method is called immediately and the string is wrapped. Going through the QueryCacheModule::getFromQueryCache produces the following stack trace

This was previously mentioned in #46

Argument 1 passed to Illuminate\Database\Grammar::columnize() must be of the type array, string given, called in D:\xampp\htdocs\j2e_laravel\vendor\laravel\framework\src\Illuminate\Database\Query\Grammars\Grammar.php on line 143 {"exception":"[object] (TypeError(code: 0): Argument 1 passed to Illuminate\\Database\\Grammar::columnize() must be of the type array, string given, called in D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Query\\Grammars\\Grammar.php on line 143 at D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Grammar.php:125)
[stacktrace]
#0 D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Query\\Grammars\\Grammar.php(143): Illuminate\\Database\\Grammar->columnize('homework_id')
#1 D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Query\\Grammars\\Grammar.php(91): Illuminate\\Database\\Query\\Grammars\\Grammar->compileColumns(Object(Rennokki\\QueryCache\\Query\\Builder), 'homework_id')
#2 D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Query\\Grammars\\Grammar.php(65): Illuminate\\Database\\Query\\Grammars\\Grammar->compileComponents(Object(Rennokki\\QueryCache\\Query\\Builder))
#3 D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Query\\Builder.php(2264): Illuminate\\Database\\Query\\Grammars\\Grammar->compileSelect(Object(Rennokki\\QueryCache\\Query\\Builder))
#4 D:\\xampp\\htdocs\\j2e_laravel\\vendor\
ennokki\\laravel-eloquent-query-cache\\src\\Traits\\QueryCacheModule.php(158): Illuminate\\Database\\Query\\Builder->toSql()
#5 D:\\xampp\\htdocs\\j2e_laravel\\vendor\
ennokki\\laravel-eloquent-query-cache\\src\\Traits\\QueryCacheModule.php(132): Rennokki\\QueryCache\\Query\\Builder->generatePlainCacheKey('get', NULL, NULL)
#6 D:\\xampp\\htdocs\\j2e_laravel\\vendor\
ennokki\\laravel-eloquent-query-cache\\src\\Traits\\QueryCacheModule.php(116): Rennokki\\QueryCache\\Query\\Builder->generateCacheKey('get', NULL, NULL)
#7 D:\\xampp\\htdocs\\j2e_laravel\\vendor\
ennokki\\laravel-eloquent-query-cache\\src\\Traits\\QueryCacheModule.php(77): Rennokki\\QueryCache\\Query\\Builder->getCacheKey('get')
#8 D:\\xampp\\htdocs\\j2e_laravel\\vendor\
ennokki\\laravel-eloquent-query-cache\\src\\Query\\Builder.php(20): Rennokki\\QueryCache\\Query\\Builder->getFromQueryCache('get', 'homework_id')
#9 D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Builder.php(571): Rennokki\\QueryCache\\Query\\Builder->get('homework_id')
#10 D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Builder.php(555): Illuminate\\Database\\Eloquent\\Builder->getModels('homework_id')
#11 D:\\xampp\\htdocs\\j2e_laravel\\app\\Listeners\\Homework\\ClearUserOldClassNotifications.php(41): Illuminate\\Database\\Eloquent\\Builder->get('homework_id')

public function selectSub($query, $as)

When passing a raw query as a string, the if statement used to check whether to append cache tags produces an error as the get_class is expecting an object to be passed.

local.ERROR: get_class() expects parameter 1 to be object, string given {"userId":22,"exception":"[object] (ErrorException(code: 0): get_class() expects parameter 1 to be object, string given at D:\\xampp\\htdocs\\j2e_laravel\\vendor\
ennokki\\laravel-eloquent-query-cache\\src\\Query\\Builder.php:49)
[stacktrace]
#0 [internal function]: Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError(2, 'get_class() exp...', 'D:\\\\xampp\\\\htdocs...', 49, Array)
#1 D:\\xampp\\htdocs\\j2e_laravel\\vendor\
ennokki\\laravel-eloquent-query-cache\\src\\Query\\Builder.php(49): get_class('SELECT `date` F...')
#2 D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Support\\Traits\\ForwardsCalls.php(23): Rennokki\\QueryCache\\Query\\Builder->selectSub('SELECT `date` F...', 'last_login')
#3 D:\\xampp\\htdocs\\j2e_laravel\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Builder.php(1533): Illuminate\\Database\\Eloquent\\Builder->forwardCallTo(Object(Rennokki\\QueryCache\\Query\\Builder), 'selectSub', Array)
#4 D:\\xampp\\htdocs\\j2e_laravel\\app\\Http\\Controllers\\Management\\SearchController.php(75): Illuminate\\Database\\Eloquent\\Builder->__call('selectSub', Array)

If you're happy for me to submit a PR I can make the necessary changes.

Thanks,
Luke

[feature] Put back into cache upon fired events on the models

Hi,
I was using this amazing package on my project.
I have requirement to modify cache content directly, in parralel with the update of database. So I could prevent re query everytime. So I need to get the key of a cache.

I'm using newest version and using redis as my cache driver

After making some debug into redis every key looks like prefixed with string like this
my_project_database_my_project_cache:015cd49cea3e5add0c86b2e6940d434f0e2b1353:leqc:theactualkey

I just want to ask, where is 015cd49cea3e5add0c86b2e6940d434f0e2b1353 come from?

Cache Flushing on Update does not Work with Relationships

When making data changes (inserts, updates, and deletes) from one model/table to another model/table via Eloquent Relationships, the protected static $flushCacheOnUpdate = true; feature does not seem to recognize that a change occurred. For instance, if I have a model/table called foo that has a function that edits a thingamajig and then edits the related thingamabobs in the model/table bar via a relationship in the foo model. When Laravel/Eloquent retrieves the data for me to view the listing of thingamabobs from bar (retrieving the data through the bar model), the data displayed is still the old data from the cache. If I comment-out use Rennokki\QueryCache\Traits\QueryCacheable; and use QueryCacheable; in the model bar, then making such edits in the foo model (via relationships) will properly display the edits pertaining to bar.

This issue appears to only be relevant to data changes via relationships. When using the bar model (i.e. use bar;) within the foo model, this issue does not occur. It is as if QueryCacheable does not recognize relationships properly.

I hope I clearly explained and described this issue. If not, feel free to ask for clarification.

Some query not caching.

Some query not caching...

use Rennokki\QueryCache\Traits\QueryCacheable;
class Event extends Model {
    use QueryCacheable;

    protected $cacheFor = 60 * 60; // 1 hour

    protected static $flushCacheOnUpdate = true;

    /**
     * Set the base cache tags that will be present
     * on all queries.
     *
     * @return array
     */
    protected function getCacheBaseTags(): array
    {
        return [
            'event_tag',
        ];
    }
}

i put this on every models, with different tag each model...

but some query is not caching why..?.
and how i can check is that my query is caching..?.,
if not caching how i can check, why thats query is not cache...

thankyou...
sorry for my english...

Purge Cache

First off, thanks so much for this!

I was just wondering if there's any means by which I can purge the cache entirely?

As an example use case:

  • Data is cached for 1 week
  • If new data is added (handled by one of the controllers), purge the cache once the new data is added, and this will then be cached for one week or until new data is added

Caching is not working for 'loadCount'

Thanks for the great package!

I have trouble with Laravel's loadCount method. Could you please give your advice for a workaround?

$user->loadCount(['phones' => function ($query) {
    return $query->cacheFor(now()->addMonths(3));
}]);

Query is

select `id`, (select count(*) from `phones` where `users`.`id` = `phones`.`user_id`) as `phones_count` 
from `users` where `users`.`id` in ('1');

get method is not support string type

if it not support ,when we are require it ,laravel will report a error .
For example:
User::where(["id"=>1])->get("name")->toArray();

for laravel is support;
for laravel-eloquent-query-cache is not support;

Bug with tags on cache driver 'file'

Screenshot 2020-05-21 at 13 30 53

The problem is with the return in QueryCacheable->newBaseQueryBuilder(), it returns
    `return $builder->cacheBaseTags($this->getCacheBaseTags());`

It should have a base tags check like:

    // changed so it could work without base tags
    if ($this->cacheBaseTags) {
        $builder
       ->cacheBaseTags($this->getCacheBaseTags());
     }
     return $builder;

BadMethodCallException getDb()

In Laravel 7, i have this:

Call to undefined method Rennokki\QueryCache\Query\Builder::getDb()

Bad Method Call

Did you mean Rennokki\QueryCache\Query\Builder::get() ?

Lumen 8.x Support

Hello. Is there any way to use this library with Lumen 8.x? Thank you.

Cache does not work for array driver

Controller:

public function test()
{
    Field::query()->cacheFor(60)->get();
    return view('welcome');
}

This is when using file driver, refreshed twice:
image

This is when using array driver, refreshed twice:
image

Enable a global CACHE_FOR= in .env file

Instead of having to manually specify protected $cacheFor in every model, simply apply env('CACHE_FOR', 0) on every Model where use \Rennokki\QueryCache\Traits\QueryCacheable; trait is installed :)

cache for individual users

I have a table in the database that assigned a model to. This table has a user_id and I want to cache the queries for the user individually. In other words, I need users to have their own specific cache so that I do not remove a global cache when invalidate. I did a prefix ->cachePrefix('m'.$user_id.'_') but do not know how to invalidate on update/insert/delete. Please can you help?

global cache invalidation

I needed to clear cache on logout so I imported the trait in my controller and did this

public function logout() {
            admins::flushQueryCache();
            invitations::flushQueryCache();
            customers::flushQueryCache();
            rides::flushQueryCache();
            users::flushQueryCache();
}

am I doing something wrong?

ReadMe Error

composer require rennokki/rennokki/laravel-eloquent-query-cache
to
composer require rennokki/laravel-eloquent-query-cache

isCache() method

How to find out whether data is being taken from the cache or from the database?
For example, there might be an isCache() method that returns true / false.
So that you can perform the action if not from the cache.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.