i am working on yii2 basic and when i update a form, data update in db successfully but update data dnt show in form even after refresh link but when i hard refresh or remove cache then it shows updated data in form , what could be a possible issue ? , because it was working fine few days before but suddenly it starts showing this behavior even an other application is in same server that is working fine , i need help .
is it yii2 configuration issue or server configuration issue?
in db.php i have these two values
'enableSchemaCache' => true,
'enableQueryCache' => false,
i tried enable schema cache to false but no luck.
Seems like there's some sort of (data) caching enabled.
You can :
Check the methods you use to retrieve data from the database to see if caching has been enabled .
Such methods are : find() , findOne() , findAll() .
Check if they have been overridden or extended by your code.
If the default find() method or any of its variants have been extended, then you could also extend the afterSave() method to flush the cache after performing updates to the database.
Here's what I use in my test environment to flush the cache after performing an update .
public function afterSave($insert, $changedAttributes)
{
parent::afterSave($insert, $changedAttributes);
//Clears cache if this is an update
if( !$insert)
{
if(method_exists ($this, 'flushCache'))
{
$this->flushCache();
}
}
}
public function flushCache()
{
Yii::$app->cache->delete($this->getCacheKey());
}
protected function getCacheKey()
{
return self::getCacheKeyPrefix(). $this->getPrimaryKey() ;
}
public static function getCacheKeyPrefix()
{
return self::CACHE_PREFIX . self::getTableSchema()->name;
}
Explanation
After writing to the DB, the afterSave() event is called by Yii.
If an insert was carried out, then cache flushing is skipped. If an UPDATE was performed, then the flushCache method is called to clear the cache.
Note that you should understand how caching has been set up in your own environment and then amend flush the cache as appropriate to suit your needs.
Let me know how it goes.
Thanks and HTH.
Related
I'm using Redis to cache different parts of my app. My goal is to not make a database query when the user is not logged in, as the app's content don't get updated regularly.
I cache the archive queries in my controller, however when I type hint a model in the controller, the model is retrieved from the database and then passed to the controller:
// My route
Route::get('page/{page:id}', [ PageController::class, 'show' ] );
// My controller
public function show ( Page $page ) {
// Here, the $page will be the actual page model.
// It's already been queried from the database.
}
What I'm trying to do is to try and resolve the page from the cache first, and then if the cache does not contain this item, query the database. If I drop the Page type-hint, I get the desired result ( only the id is passed to controller ) but then I will lose the benefit of IoC, automatic ModelNotFoundException, and more.
I've come across ideas such as binding the page model to a callback and then parsing the request(), but seems like a bad idea.
Is there any way to properly achieve this? I noticed that Laravel eloquent does not have a fetching event, which would be perfect for this purpose.
You can override the default model binding logic:
Models\Page.php
public function resolveRouteBinding($value, $field = null)
{
return \Cache::get(...) ?? $this->findOrFail($value);
}
Read more here https://laravel.com/docs/8.x/routing#customizing-the-resolution-logic
In order to check for existence of the data in Redis, you shouldn't type-hint the model into the controller's action. Do it like this:
public function show($pageId) {
if(/* check if cached */) {
// Read page from cache
} else {
Page::where('id', $pageId)->first();
}
}
What I want to do:
Return a bunch of rows from database, convert in a array stored in memory and make this array visible from the whole project in such a way that other controllers for example can read it. My function is simple as that:
class BoardController extends Controller
{
/*
* returns something like
* ['name' => 'description',
...
]
*
* */
public static function getAll()
{
$boards = Board::orderBy('ordem')->get();
$retorno = array();
foreach($boards as $b)
{
$retorno[$b->sigla] = $b->nome;
}
return $retorno;
}
}
If I just keep calling BoardController::getAll() it will again read from database again. I also tried making this call inside a config file into a variable and returning it there but laravel gave me a 500 error. So, what is the best practice/way to do it?
If you don't want to call the database everytime then the best approach that can be followed here is to use caching and cache the results.
The Approach is simple, You make a Database call once and cache the reaults and the next time you hit the same function you check the cache first whether its empty or not. If its not empty, then return the cached results.
Remember, the cache has a time limit otherwise if you change/update anything in the database then you'll have to clear the cache that is already stored.
Laravel has some features for caching the results. You can see it Here.
Also You can also view this link for more effective implementation of cache in Laravel.
Hope this helps.
I have simulatneous AJAX requests on codeIgniter with all of them session update like so:
function ajax1($value)
{
$this->session->set_userdata('foo', $value);
}
function ajax2($value)
{
$this->session->set_userdata('bar', $value);
}
But sometimes because of MySQL concurrency, one variable or the other is not updated, I suppose because one method gets overwrites the new value of the other method with the old value if grabbed from the db.
I cannot update the 2 sessions at the same time as they do completely different things and I don't know which ones will be called, as the page is dynamic and might have one or several of these method calls.
Anybody ran into this in the past and has a way of going around that problem?
I think this problem was fixed in the latest version of codeIgniter, but if you are still using an old one, try to replace system/libraries/Session.php with a new one, or you can just override the Session Library like follow:
application/libraries/MY_Session.php
class MY_Session extends CI_Session
{
function sess_update()
{
if (!$this->CI->input->is_ajax_request())
return parent::sess_update();
}
}
I ran into a weird problem with Codeigniter Database Cache. I'm using it to cache one query result. For this I am enabling it at the begining of the function and disabling right after:
function checkAfter($lastCheck)
{
$this->db->cache_on();
$this->db->where('time >' , date('Y-m-d H:i:s', $lastCheck));
$q = $this->db->get('actions');
$r = $q->result();
$this->db->cache_off();
return (!empty($r)) ? $r : false;
}
I need to delete the cache on the certain event when something is added to database.
It is working fine with $this->db->cache_delete_all(); but when I'm trying to remove one specific method cache like it is explained in user guide it doesn't do anything.
What might be the problem here?
Both methods are called in the same Model. I also tried to enable cache before delete but still nothing.
EDIT
Lets say i have method checkEvents in my main controller which calls the checkAfter method of the model which then works with cache. CI cache engine creates a folder called main+checkEvents under cached forlder where chached data is stored.
so i am trying to remove it with
$this->db->cache_delete('main', 'checkEvents');
call in logEvent method (which saves the new event) of that model.
I'm working on a controller that will update a few tables. I am able to call my model from my controller and inside the model function I can make a begin and commit my query, it can rollback should an error happen.
Here is my sample:
Controller:
//update table when update button is clicked
if (!empty($this->data)) {
if ($this->Item->update($this->data)) {
$this->Item->create();
$this->redirect('/sample');
return;
} else {
$this->set('data', $this->data);
}
}
Model:
function update($data)
{
$this->begin($this);
if(!parent::save($data)) {
$this->rollback($this);
return false;
}
$this->commit();
return true;
}
Now this works fine. But what I need to do is to call another model in my controller like "$this->"ANOTHER MODEL HERE"->update()". I need to have rollback should a problem occur with either model transaction. What I'm thinking is to put a commit in my controller after both model call succeeds.
Much like this:
CONTROLLER PHP:
BEGIN TRANSACTION
->CALLS MODEL1
IF(MODEL1 == ERROR){
ROLLBACK
}
->CALLS MODEL2
IF(MODEL2 == ERROR){
ROLLBACK
}
COMMIT WHEN NO PROBLEM IS ENCOUNTERED
So is it possible to perform commit in controller? I am only able to do it in model. Thanks in advance!
So is it possible to perform commit in controller? I am only able to do it in model.
Yes, you can perform commit or rollback from within the controller. You need to get the datasource from one of your models first. In the controller code, simply reference one of the models you are using (assuming they are all in the same database):
$ds = $this->MyModelName->getdatasource();
Then you can begin, commit, and rollback to that datasource from within the controller.
$ds->begin();
// do stuff and save data to models
if($success)
{
$ds->commit();
}
else
{
$ds->rollback();
}
I actually have a rollback or commit in more than one place if I am bailing on the action and redirecting or finalizing in some step and redirecting. I just illustrate a simple case here.
Handling transactions in the controller makes the most sense to me since the controller action is where the transaction boundaries really reside conceptually. The idea of a transaction naturally spans updates to multiple models. I have been doing this using postgres as the back end database with Cake 2.2 and 2.3 and it works fine here. YMMV with other db engines though I suspect.
Trasactions are to be enhanced in futures versions of CakePHP, as you can see in this CakePHP Lighthouse ticket.
There are two possible solutions proposed there, and I am showing you a third one. You could create a custom method to save it, and manually commit the transactions:
public function saveAndUpdate($data) {
$ds = $this->getDataSource();
$ds->begin();
if ($this->save($data)) {
foreach(Array('Model1', 'Model2') as $model) {
if (!ClassRegistry::init($model)->update()) {
$db->rollback();
return false;
}
}
return $db->commit() !== false;
}
return false;
}
I wrote this code to illustrate how I though about your problem, although I didn't test.
More useful links:
Transactions at CakePHP Book
About CakePHP Behaviors
How to create Behaviors
I used commit within my if statements and rollback in my else statements. Since I was using two different models from within a controller, I created two different datasources
$transactiondatasource = $this->Transaction->getDataSource();
$creditcarddatasource = $this->Creditcard->getDataSource();
$transactiondatasource->begin();
$creditcarddatasource->begin();
if (CONDITION){
$creditcarddatasource->commit();
$transactiondatasource->commit();
CakeSession::delete('Cart');
} else {
$this->Session->setFlash(__('MESSAGE'));
$creditcarddatasource->rollback();
$transactiondatasource->rollback();
}