how update cached data when main data is change in laravel - laravel

i want to use a cache of laravel for ex: index method on a specific controllers!
i use Cache::rememberForever method of laravel cache.
i dont use Cache::remember with ttl time for caching data!
my question: i dont no when and how i update data in cache
imaging: i cached user profile with all relations! now user change avatar or personal data! now i should be renew (update) cache data in redis! (update cache data for get in next call) i want to know the best solution for updating cache data when update main data

To update a cache you can use such. event function in your User model:
protected static function boot()
{
parent::boot();
$removeCacheFunc = function ($model) {
$key = self::USER_CACHE_KEY . $model->id; //compile cache key in your way
\Cache::delete($key);
};
static::saved($removeCacheFunc);
static::deleting($removeCacheFunc);
}
Next time you call Cache::rememberForever() will not find this entity by key and will make it on the fly

Related

Laravel deleting cache working in controller but not in model closure

I'd like to delete a specific model from the cache using its id. This works as expected in the controller, but not using the model closure.
What I have in App\Models\Post:
use Illuminate\Support\Facades\Cache;
protected static function booted()
{
static::updated(function ($post) {
Cache::forget('post:'.$post->id);
});
}
If I do Cache::forget('post:'.$post->id); in the controller it works.
Something I'm missing?
Make sure that you are actually changing a value on your model, because the updated event only fires when the model was dirty, as you can see here.
The saved event however will fire whenever you call the save() method, as you can see here:
protected static function booted()
{
static::saved(function ($post) {
Cache::forget('post:'.$post->id);
});
}
From the docs:
The retrieved event will fire when an existing model is retrieved from
the database. When a new model is saved for the first time, the
creating and created events will fire. If a model already existed in
the database and the save method is called, the updating / updated
events will fire. However, in both cases, the saving / saved events
will fire.

View Share doesn't return updated data, how then to share live data?

I currently have a model which access data like so:
$currentSessionID = session()->getId();
$displayCart = Cart::where('session_id', $currentSessionID)->get();
return view('layouts.cart')->with('cartDetails', $displayCart);
This model correctly retrieves the data in a current session.
To access this same data in a header file I'm using View::Share in the AppServiceProvider like so:
public funciton boot()
{
$currentSessionID = session()->getId();
$inCartDetails = Cart::where('session_id', $currentSessionID)->get();
View::share('inCartDetails', $inCartDetails);
}
In my blade the $inCartDetails returns empty. I get [].
My suspicion is that this function ONLY gets called at boot. Hence the name :) and that it's empty cause at the time of starting the session it's empty since user hasn't selected anything. If this is correct how would I then pass live data to multiple views?
The session is not available in the boot method of the service providers. You should create a middleware for this. Check out this answer here: How to retrieve session data in service providers in laravel?

Laravel5.5: save Provider data in session to avoid overload

I have made a ServiceProvider to load data on several views. Like this:
View::composer(['components.navigation.main.search','search.*','page-parts.cats','page-parts.categories_menu','page-parts.categories_more','page-parts.cats_top','components.modals.off-category'],function ($view) {
$view->with([
'toplevel_categories' => Category::topLevel()->orderBy('name')->get(),
]);
});
But on several html pages he needs to load multiple of these views and I don't want to load the topLevel categories each time to avoid overload and less runtime.
Can I store the loaded data (toplevel_categories) in a session or what is the most efficient way to handle this problem?
You could simply cache the variable and use it in the callback like:
$topLevelCategories = Category::topLevel()->orderBy('name')->get();
View::composer([], function($view) use ($topLevelCategories) {
$view->with([
'toplevel_categories' => $topLevelCategories
}
You could even use the cache mechanic from laravel itself to save an additional query, like caching it for 30 minutes (assuming the database hasnt changed in the meantime):
// Save the categories in the cache or retrieve them from it.
$topLevelCategories = Cache::remember('topLevelCategories', 30, function() {
return Category::topLevel()->orderBy('name')->get();
});
Note that for Laravel 5.8 the second parameter is in SECONDS, for 5.7 and below it is in MINUTES.
Since your service provider is only loaded once per request/lifecycle this should do the trick.

Laravel How to store extra data/value in session Laravel

I'm using default auth() in laravel login (email & password)
Now i try to take input from the user in text field like (Age or City)
Now i want to store (Age/City) in my session.
Help me
You can use session() helper:
session('age', 18); // saves age into session
$age = session('age')`; // gets age from session
Update
If you want to save Age and City after user registration, you should store this data in a DB, not in a session. You can add some fileds in create method of app\Http\Controllers\Auth\AuthController.php
You can use
Session::put('key', 'value');
To get key from Session use
Session::get('key');
You can use the session() helper function as #Alexey Mezenin answer.
Laravel Session Documentation
Ok let me enlighten you. if you want to store it in session do it this way.
session('country', $user->country); // save
$country = session('country')`; // retrieve
But that is not the way we do in Laravel like frameworks, it uses models
once the user is authenticated each time when we refresh the page, application looks for the database users table whether the user exists in the table. the authenticated user model is a user model too. so through it we can extract any column. first thing is add extra fields to the User class(Model) $fillable array.
so it would look something like this.
User.php
protected $fillable = ['username', 'password', 'remember_token', 'country'];
so after simply logging in with user name and password in anywhere just use Request class or Auth facade. Facades are not too recommended so here for your good as a new one i would just say how to use Request. Suppose you want to retrieve your Authenticated user country inside TestController.php here is how it could be used in the methods.
TestController.php
use Illuminate\Http\Request;
public function testMethod(Request $request)
{
$someCountry = $request->user()->country; //gets the logged in user country
dd($someCountry); //dd is die and dump, could be used for debugging purposes like var_dump() method
}
Using Request
public function ControllerName (Request $request){
$request->session()->put('session_age', $age);
}
Get session_age
$get_session_age = $request->session()->get('session_age');
Using Session
public function ControllerName (){
Session::put('age',$age);
}
Get the session
$session_age = Session::get('age');
Don't forget to define Session or Request in your controller!!!
use App\Http\Requests;
use Session;
To work with session in your controller you need to include session first in your controller
use Session;
After that for store data in session. There is several ways to do it. I prefer this one (in controller)
session()->put('key',$value);
To display session data in your View you can do it like this
#if(Session::has('key'))
I'v got session data
#else
I don't have session data
#endif
To get session data in your Controller you can do it like this
session()->get('key')
//or
session()->get('key','defaul_value_if_session_dont_exist')
When you are done with your data in session you can delete it like this (in controller)
session()->forget('key');
All this basic usage of session is well documented in official Laravel documentation here.
Hope it helps you

Symfony 1.4 functional test not displaying new data

I'm running a functional test against my Symfony 1.4 project and it keeps failing because it doesn't fetch the latest data.
The test makes up a new site entry, then a survey at the site, then adds data to the survey. Each of these are on separate pages and each work. The data is definitely present in the database. After saving the last form, the survey_data, it returns to the survey page where it should get the survey details and a list of all the data items added to it. This works in dev and prod environments but in my functional tests the survey_data list is empty. Looking through the logs it doesn't try to fetch the data from the database (Doctrine & Postgres). But if I manually load the page in a browser just seconds later the list is there, and if I run a test that goes directly to the page (without clearing the database) the list is there, so the test login has the rights to see that page and the contents, but won't show it at first, as if it has cached the page survey page before the survey_data was added.
So my question is, how can I ensure my functional tests get the latest data from the DB or how can I refresh the local data object cache after saving a new item to the database?
Additional:
My functional tests extend sfPHPUnitBaseFunctionalTestCase and I use the sfBrowser class to check the contents of the pages and navigate through them
The issue appears to be with Doctrine caching any objects it updates for the duration of the execution. This gets cleared out after each web request in a production environment - one request per execution - but in the test environment it appears to persist between requests as they're all happening in the same execution.
It becomes troublesome when testing the process of, say, adding a new Item to a List - the List is in memory (test browser has been to its page before), the new Item gets created, saved but the link between them isn't formed in-memory.
Targeted refreshing of related objects
If you know what object you're looking to forcibly refresh you can:
$SomeDoctrineRecordObject->refreshRelated(); // for all relationships
$SomeDoctrineRecordObject->refreshRelated($relation); // for a specific one
( for the above List and Item example, you'd $list->refreshRelated('item') )
This is only useful if you're using the Doctrine object already, else you have to go pull it out of the route or database each time you need to refresh it. A more general approach is to extend the sfTestFunctional class and override the methods which might result in a relationship change and thus need to trigger a refresh.
General refreshing of all objects
The code to clear out Doctrine's object cache:
$manager = Doctrine_Manager::getInstance();
$connection = $manager->getCurrentConnection();
$tables = $connection->getTables();
foreach ( $tables as $table ) {
$table->clear();
}
And an example of how to hook it into a custom functional test object:
class myTestFunctional extends sfTestFunctional
{
public function get( $uri, $parameters = array(), $changeStack = true )
{
$this->clearEntityCache();
return parent::get( $uri, $parameters, $changeStack );
}
public function click( $name, $arguments = array(), $options = array() )
{
$this->clearEntityCache();
return parent::click( $name, $arguments, $options );
}
protected function clearEntityCache()
{
$manager = Doctrine_Manager::getInstance();
$connection = $manager->getCurrentConnection();
$tables = $connection->getTables();
foreach ( $tables as $table ) {
$table->clear();
}
}
}
Thus every time myTestFunctional gets a url or clicks to change page it clears out any Doctrine objects stored in memory. Not subtle, but effective and doesn't make the tests themselves more labourious to write!

Resources