CodeIgniter $this->session->set_userdata() on 2 simultaneous AJAX - php

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();
}
}

Related

How to get data, passed by a view composer to certain views, inside the controller?

My View Composer passes some data to certain views (and it works, of course):
use Illuminate\View\View;
use App\Util\Helper
class PublicSettingsComposer
{
public function compose(View $view)
{
$view->with('settings', Helper::readSettingsFromFile()); // json
}
}
The appropriate provider is added into the configuration and it provides this composer correctly for all specific views:
view()->compose('public.layouts.*', 'App\Http\ViewComposers\PublicSettingsComposer');
However, inside (only) one of my views I need specific information from database, but therefore I have to use some data, that had been passed by my View Composer:
class BranchController extends Controller
{
public function branches()
{
$settings = retrieve_settings_passed_by_PublicSettingsComposer; // This is what I need
$headquartersId = $settings->headquartersid;
return view('public.layouts.branches', [
'headquarters' => Branch::find($headquartersId) // Branch is a Model
]);
}
}
FYI: Laravel version I'm using is: 5.5
P.S. #moderators: Please, be careful with considering my question as a duplicate. I know there are many questions about view composers and passing data to the views and grabbing data from within controllers. However, I really could not find any question with this context (titles are often misleading).
I see two rather simple solutions for this. The first one is to cache the parsed file within each request. The other is to use an actual cache for this job.
The first option is very straight forward to implement. In your Helper class you'll have to introduce a static property to hold the parsed contents of the read file. Then, just like you do within the singleton pattern, you either return the cached data or you first parse the file, cache the data and return it afterwards. This scenario solves your actual problem of parsing the settings twice per requests if used in two places of your app.
class Helper
{
protected static $cachedSettings;
public function readSettingsFromFile()
{
if (!self::$cachedSettings) {
self::$cachedSettings = // Do the parsing here. This should be your current implementation of Helper::readSettingsFromFile(). You can also put this in its own function.
}
return self::$cachedSettings;
}
}
The other option is to use an actual cache (an external one). You can either cache the parsed file for a specific amount of times (like 1, 3, 5 or 10 minutes or even longer). Or you cache it forever and invalidate the cache when you update the settings (if this happens within your app and you know it was updated).
This solution does only make sense if your settings do not change too frequently though. It also depends a bit on the amount of requests you expect towards your app. If your settings change not too frequently (less than every x minutes) and your app is used frequently (multiple requests every x minutes), then it could be a viable solution.
class Helper
{
public function readSettingsFromFile()
{
return Cache::remember(function () {
$settings = // Put your current calculation here
return $settings;
}, 3 * 60); // 3 * 60 = 180 seconds
}
}

kohana ajax controller sessions are not working with auto render

Using ajax function working with sessions. In controller with ajax action i'm setting the session values using $this->session->set('coupons',$data). After setting this session i'm not able to get in another controller file already added session.Can you pls advice me.
public function action_applypcode()
{
$this->auto_render = false;
$this->session->set('coupon_details', $restcode);
}
public function action_receipt()
{
$coupon_details = $this->session->get('coupon_details');
print_r($coupon_details);
//Here getting empty session values
}
What is $restcode?
You shouldn't have any problem on setting session values through ajax or normal request, they work equally, the only diff is that you don't want the layout form ajax calls.
Are you using another lib or module that could initialize a session too? Search in your external modules for $_SESSION, sometimes that can be the problem. If that's the problem, try using Session::instance() at the first line of your template controller.
Btw, I don't remember kohana having an attr for the session in the controllers, also you can try using Session::instance()->set and ->get , maybe that could help too.
Regards!

View composer runs multiple times, how to reduce to 1

I made a view composer in Laravel 5. When i use a wildcard *, to add something to all my views, it get's called at least twice. It runs when my master template is loaded, and again when my content page is included. This will give problems in the future, because it executes the query it does multiple times. I was able to fix the multiple querying by storing it in a static variable :
class StoreComposer {
static $composed;
public function __construct(StoreRepository $repository)
{
$this->store = $repository;
}
public function compose(View $view)
{
if(static::$composed)
{
return $view->with('store', static::$composed);
}
static::$composed = $this->store->pushCriteria( new WithCategories() )
->pushCriteria( new WithSettings() )
->applyCriteria()
->all();
$view->with('store', static::$composed);
}
}
My question is, is there a way to make sure it only runs once, no matter how many views i load, or is there another solution to this? The way i fixed it now doesn't feel right to me. Thanks!
Unfortunately no, there is no way to make it run once, due to the way View Composers are implemented. The Illuminate\View\View::renderContents() method is responsible for calling the composer bound to a view, and since any form of view rendering (Blade template inheritance or simple #include statements) executes that method, it means that when any view is rendered any composer bound to it gets triggered.
Since in your case you use a * wildcard to bind all views, if your page renders ten views, the composer will get executed ten times. However your approach looks like a good solution to solve this shortcoming.
You can use config here to resolve multiple times query run issue for example show below code.
public function compose(View $view)
{
if(!Config::has('composeVars'))
{
Config::set('composeVars') = [
'data' => User::all();
];
}
$view->with('*', Config::get('composeVars'));
}
Try this singleton solution or use cache https://laracasts.com/discuss/channels/laravel/executing-a-view-composer-only-once
On Laravel 5.6.38 works fine

CodeIgniter, Accessing class property after page reloads, is it possible?

I have a CI page that will load to a div in view file, using jQuery. Using switch(page_parameter), I control what is showing from the page.
When I call the page for 3rd time, I set a value to the class array.
But when I call the 4th time, the array become empty.
I was wondering, is it actually possible to use the class property to store value that can be used after page re-access? Or something missing in my head?
I know that using session is not a good idea, since the real array is a big chunk of serialized xml.
Here's my code:
class MyClass extends MY_Controller
{
public static $pitems = array();
function Hotel(){
parent::MY_Controller();
}
function new_campaign(){
$params = $this->uri->uri_to_assoc();
switch($params['step']){
case '3' : self::$pitems = array("test","another"); //here the class array was set successfully
$this->load->view('viewer');
break;
case '4' : print_r(self::$pitems); //here the array is empty
break;
}
}
In the viewer page, there's a call to the page:
Next page
Same issue also with $this->
What am i missing here?
Thanks in advance~
edit:
I saw a script that has similar scenario. it successfully reused the variable set in the constructor, instead of treating it as a class variable. i'll look thorough to confirm this, but for now, i'll close this thread. Thanks Chris for sharing.
Im not really sure what your trying to do but I have users jQuery post()/get()/ajax() many of times in CI and have had no problems. So despite not knowing or understanding what your trying to do. I thought I'd at least say I know loading data without refresh in CI through something like jQuery isn't an issue. Example on system I built on CI had a twitter like feed of tweets where jQuery on a timer was polling for new data and coming back with it each time accordingly if something new was to be shown.

Reduce database calls for php web shop

I'm looking for a way to prevent repeated calls to the database if the item in question has already been loaded previously. The reason is that we have a lot of different areas that show popular items, latest releases, top rated etc. and sometimes it happens that one item appears in multiple lists on the same page.
I wonder if it's possible to save the object instance in a static array associated with the class and then check if the data is actually in there yet, but then how do I point the new instance to the existing one?
Here's a draft of my idea:
$baseball = new Item($idOfTheBaseballItem);
$baseballAgain = new Item($idOfTheBaseballItem);
class Item
{
static $arrItems = array();
function __construct($id) {
if(in_array($id, self::arrItems)){
// Point this instance to the object in self::arrItems[$id]
// But how?
}
else {
// Call the database
self::arrItems[id] = $this;
}
}
}
If you have any other ideas or you just think I'm totally nuts, let me know.
You should know that static variables only exist in the page they were created, meaning 2 users that load the same page and get served the same script still exist as 2 different memory spaces.
You should consider caching results, take a look at code igniter database caching
What you are trying to achieve is similar to a singleton factory
$baseball = getItem($idOfTheBaseballItem);
$baseballAgain =getItem($idOfTheBaseballItem);
function getItem($id){
static $items=array();
if(!isset($items[$id])$items[$id]=new Item($id);
return $items[$id];
}
class Item{
// this stays the same
}
P.S. Also take a look at memcache. A very simple way to remove database load is to create a /cache/ directory and save database results there for a few minutes or until you deem the data old (this can be done in a number of ways, but most approaches are time based)
You can't directly replace "this" in constructor. Instead, prepare a static function like "getById($id)" that returns object from list.
And as stated above: this will work only per page load.

Categories