Problem
Session::get not working in Base Controller
Below case does not shows correct session value
Login Controller
class LoginController extends \App\Http\Controllers\Web\BaseController
{
public function Login() {
return View("UserManagement.Auth.Login.login");
}
}
Base Controller
class BaseController extends Controller
{
public function __construct() {
if(\Session::get("CurrentLanguage") != null) {
dd('here');
\App::setLocale(\Session::get("CurrentLanguage"));
}
else {
dd('here1');
\Session::put("CurrentLanguage", "en");
\App::setLocale("en");
}
}
}
Below case shows correct session value
Base Controller
class BaseController extends Controller
{
}
Login Controller
class LoginController extends \App\Http\Controllers\Web\BaseController
{
public function Login() {
if(\Session::get("CurrentLanguage") != null) {
dd('here');
\App::setLocale(\Session::get("CurrentLanguage"));
}
else {
dd('here1');
\Session::put("CurrentLanguage", "en");
\App::setLocale("en");
}
return View("UserManagement.Auth.Login.login");
}
}
Here the problem is, I have to use Base Controller in many controllers. Is there any way to make the session work in Base Controller?
According to the following URL, you are no longer able to use the session in the constructor of a controller in Laravel 5.3. This is because at the point in time that your controller is constructed the middleware that deals with the session has not yet run. Apparently, it was never an intended feature to be able to access the session in the controller. Since this affected sessions, you will not be able to access the authenticated user in the controller's constructor either.
A way around this however is to use a closure based middleware in your constructor.
class BaseController extends Controller
{
public function __construct()
{
$this->middleware(function ($request, $next) {
if(\Session::get("CurrentLanguage") != null) {
dd('here');
\App::setLocale(\Session::get("CurrentLanguage"));
}
else {
dd('here1');
\Session::put("CurrentLanguage", "en");
\App::setLocale("en");
}
return $next($request);
});
}
}
This works because your controller is simply defining a middleware to run at a later time after which the session is available.
The reason it works in your second example is that you're accessing the session in a controller method. At that point in time the session is available because the middleware will have run.
Related
I'm inside a Laravel controller. I only want the init() method to fire once. What actually happens is, it fires every time I run the controller/methods via a browser?
class MyController extends Controller
{
public function __construct()
{
static $init_called = false;
if(!$init_called){
$init_called = true;
$this->init();
}
}
public function init()
{
// initialize code here, execute 'once' only
}
public function routeOne(){}
public function routeTwo(){}
}
One solution is to store a value on session or on database. This value allow you to know if the function has already been called.
Then check the value at the top of the method every time it's is fired.
if it's true you can proceed to the normal instructions else you exit the function.
Since Http is a stateless protocol I'm probably attempting something outside of the realms of possibility. As a workaround, I used the following:-
// Call this route once only
Route::get('/init', [MyController::class, 'init'])->name('initialize');
class MyController extends Controller
{
public function init()
{
MyModel::persistData();
}
}
class MyModel extends Model
{
private $data;
public static function persistData()
{
$data = ['some data'];
MyModel::insert($data);
}
}
This is a part of the code.
class StudentController extends Controller
{
public function __construct(Request $request)
{
$school = session('school_data');
$this->middleware($school);
}
}
Now, I've also tried checking the $school by using dd($school) but it returns null
NOTE: The session variable works in other functions inside the same controller.
your sessions are not ready yet.
if you want to use them, use like below:
class StudentController extends Controller
{
public function __construct(Request $request)
{
$this->middleware(function ($request, $next) {
// fetch session and use it in entire class with constructor
$this->school_data = session()->get('school_data');
return $next($request);
});
}
}
from here: laravel - Can't get session in controller constructor
I will give below code example to better explain:
class BaseController extends Controller
{
public $globalCurrencies;
public $currentCurrency;
public $globalLanguages;
public $currentLanguage;
public function __construct()
{
$this->globalCurrencies = $this->getCurrencies();
$this->globalLanguages = $this->getLanguages();
$this->middleware(function ($request, $next) {
$this->currentCurrency = $this->getCurrentCurrency();
$this->currentLanguage = $this->getCurrentLanguage();
return $next($request);
});
}
CartController
class CartController extends BaseController
{
public function __construct()
{
parent::__construct();
}
BaseController sets up base variables for the app. The cart is using some of them like (current currency). Some of the variables are session based so in base construct there is middleware used to get session data in the constructor). For this part, everything works and cart has access to baseController properties.
Problem occurs here:
class OrderController extends BaseController
{
public function loadPaymentsAndDelivery(Request $request)
{
$cart = new Cart;
dd($cart->globalCurrencies) // WORKS
dd($cart->currentCurrency) // NULL
}
}
Basically, on a new Cart instance, I can access every property created without middleware. Without middleware, I cannot access the session to set up the cart. Method loadPaymentsAndDelivery is loaded via ajax but I tried directly call the method and the properties were still null.
Can somebody explain why this is happening?
We want to pass data from controller to another controller in Laravel (framework). In our Controller.php we got a middleware code in the __construct function, which sets a environment and person.
Code in Controller.php
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->environment = session()->get('environment');
$this->person = session()->get('person');
return $next($request);
});
}
In a different controller we pass 2 parameters (Request data) and (id of data) to another controller function. We tried many ways for pass data. On this moment we lost our $this data like environment and person, the variables environment and person are exists but empty.
We tried with:
$postController = new \App\Http\Controllers\Publication\Post\IndexController();
$postController->duplicate($request, data_get($publication, 'id'));
Or
app('App\Http\Controllers\Publication\Post\IndexController')->duplicate($request, data_get($publication, 'id'))
In Post\IndexController#duplicate we lose our $this data (empty).
We tried to get data like $this->enviroment but this variables are empty.
Anyone has any idea how to pass data with the variables filled by the middleware?
You can use the power of Container
Code in Controller.php
public function __construct()
{
$this->middleware(function ($request, $next) {
app()->instance('person', session()->get('person'));
app()->instance('environment', session()->get('environment'));
return $next($request);
});
}
In another controller:
<?php
namespace App\Http\Controllers;
class DupeController extends Controller
{
public function index()
{
dd(app('person'));
}
}
Just make sure if the "another controller" has it's own constructor, call the parent constructor, you your 'person' and 'environment' instance would be available in that controller.
<?php
namespace App\Http\Controllers;
class DupeController extends Controller
{
public function __construct()
{
parent::__construct();
// DO MAGIC
}
public function index()
{
dd(app('person'));
}
}
But I gotta tell you the truth, this is a bad practice. I just want to show you that something bad like this is possible. Try another approach like service injection to the controller using dependency injection technique and mark that service as a singleton, so container will resolve the same instance for every resolution (one instance per request).
I am trying to redirect to controller index if not authorized the access to other functions within same controller. According to my coding it is looking like infinite loop. Please help me to do that.
class Customer_Dashboard extends CI_Controller {
public function __construct() {
$method= $this->router->fetch_method();
if ($this->session->userdata("cus_sel_comp")) {
}else{
if($method !="index"){
redirect(base_url()."customer_dashboard");exit;
}
}
}
public function index() {
// Here do some operations and let the user to select company and update the "cus_sel_comp" session variable. After set that session user can access the other controller functions.
}
public function other_function1() {
}
public function other_function2() {
}
}
My coding is as above. I need to do this using same controller. Problem is if that session not set there is a infinite loop.
Instead of redirecting return index function. See the code below
if($method !="index"){
return $this->index();
}
You are calling the same function and redirecting it to same method.
class Customer_Dashboard extends CI_Controller {
public function __construct() {
$method= $this->router->fetch_method();
if ($this->session->userdata("cus_sel_comp")) {
}else{
if($method !="index"){
redirect(base_url()."Customer_Dashboard/index"); // Redirect it to index if other method is invoked.
}
}
}
public function index() {
// Here do some operations and let the user to select company and update the "cus_sel_comp" session variable. After set that session user can access the other controller functions.
}
public function other_function1() {
}
public function other_function2() {
}
}
Also dont use base_url() instead of that define an path in config
base_url() has many other entries present which are un-necessarily called.