How to know which method is called in Laravel controller - laravel

When a request comes to Laravel controller through application router, how can we determine which method is called inside that controller? I mean inside constructor or magic methods of the controller. Is it possible to know?
Consider the method that is called exists. So __call would not be the solution.
I have this Route:
Route::get('exam', [ExamController::class,'index']);
And I want to get index inside ExamController class. maybe in side __construct or ...
public function __construct()
{
// here I want to access the name of called method
}
__call magic method just give the method name if the method is'nt exist:
public function __call($method, $parameters)
{
// I have access to $method name here (index)
}

You can use the __FUNCTION__ or __METHOD__ PHP constants to obtain information about the function or class and function:
class SomeClass
{
public function aFunction()
{
echo __FUNCTION__;
}
public function anotherFunction()
{
echo __METHOD__;
}
}
$obj = new SomeClass();
$obj->aFunction(); // aFunction
$obj->anotherFunction(); // SomeClass::anotherFunction
Update
Let's assume whilst you might not have a function defined for a specific route, you know the name of a route you want to apply a specific middleware to. You can apply middelware to specific functions from the controller constructor:
public function __construct()
{
$this->middleware('auth', ['only' => ['index', 'create']]);
}
Alternatively just specify the middleware required for the route on the route definition.

Related

How to pass a parameter to a laravel controller from redirect within the same controller

How do I pass a true false value to the controller from the redirect in the class and to the router and back to another function in the same controller class if that makes sense
Like
public function 1() {
return redirect('route2');
}
public function2() {
I need to access the variable here that some how gets passed from the first function
}
Because these functions are both on my main controller and I need to pass a variable through the route
and back into the controller or is there a way to put a state variable on the class or something I just need to call a function on the controller with conditions from the previous controller function that called called the redirect route.
Also sorry if I am mixing up class and function I am new to laravel and MVC in general.
You can do something like this:
public function first() {
return redirect()->action(
[YourController::class, 'second'], ['value' => true]
);
}
public function second($value = null) {
// whatever you want
}
https://laravel.com/docs/9.x/redirects#redirecting-controller-actions
I think this code help you:
public function 1() {
return to_route('YOUR_ROUTE_NAME', ['value' => 'some things...']);
}
public function2(Request $request, $value) {
// Use the value passed as a route parameter
// $value is 'some things...'
}

Access session data from parent controller w/o passing it in

Can I access session data from Controller, without passing the request from MyController?
class Controller extends BaseController
{
public function __construct()
{
// ** next line throws error:
// "Session store not set on request."
$userdata = request()->session()->get('userdata');
// I want to inject `userdata` into every template without
// passing data from child controllers.
view()->share(['userdata' => $userdata);
}
}
class MyController extends Controller
{
public function __construct(Request $request)
{
// This works, so the data is in fact in the session.
// I don't want to pass it, or `$request` to the parent from here.
$userdata = $request->session()->get('userdata');
...
}
}
The reason it won't be working in your __construct() method is because the StartSession middleware won't have been run yet.
To get around this you can simply use the middleware() method on the controller:
public function __construct()
{
$this->middleware(function ($request, $next) {
$userdata = $request->session()->get('userdata');
view()->share(compact('userdata'));
return $next($request);
});
}
Laravel 5.3 Upgrade guide (Scroll down the Controllers section)
In Laravel 5.3, you can't access the session or authenticated user in your controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly in your controller's constructor.

laravel Controller error when using Request in function

I make controller by using php artisan make:controller newsController --resource
And after that when I go to my controller in function index, I want to add Request $request
public function index(Request $request)
{
}
It's return error:
Declaration of
App\Http\Controllers\Admin\NewsController::index(Illuminate\Http\Request
$request) should be compatible with
App\Http\Controllers\Controller::index()
How to fix it? I try many way but it still didn't work!
EDIT — Controller
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
UPDATED — Routes
Route::post('admin/news', 'Admin\NewsController#store');
Route::resource('admin/news', 'Admin\NewsController');
It's quite simple, just create your Resource controller without the index route Or Create new get route, like this:
Route::resource('admin/news', 'Admin\NewsController', ['except' => ['index']]);
Then add your route before the resource declaration, something like this:
Route::post('admin/news', 'Admin\NewsController#index');
Route::resource('admin/news', 'Admin\NewsController', ['except' => ['index']]);
Hope this helps you!!
This doesn't require any Laravel work arounds.
Fix:
a) Remove the index method from the base controller
or
b) Make the index method in the base controller take a Illuminate\Http\Request as an argument and use that same method signature in every controller's index method that inherited from the base in the entire application.
or
c) Figure out why there is an index method defined in the base in the first place and, if needed, move it to a trait to use in child classes instead. (allows you to override the method completely)
b is not a good option, it is just to illustrate a point
Issue demonstrated:
class Foo
{
public function index()
{
//
}
}
class Bar extends Foo
{
public function index(\Illuminate\Http\Request $request)
{
}
}
Declaration of Bar::index(Illuminate\Http\Request $request) should be compatible with Foo::index()
You want to override the index action.
You also want to pass parameters into this index action.
The App\Http\Controllers\Controller::index() does not take parameters.
So they are not "compatible".
Try this "helper-funtion" way:
public function index() {
$request = request() // use the helper function
// ...you code here...
}
You can disable index from resources and define route with different method name before or after resource:
Route::get('resources', 'ResourceController#getResources');
Route::resource('resources', 'ResourceController', $restResource)->except(['index']);

Laravel 5 : passing a Model parameter to the middleware

I would like to pass a model parameter to a middleware. According to this link (laravel 5 middleware parameters) , I can just include an extra parameter in the handle() function like so :
public function handle($request, Closure $next, $model)
{
//perform actions
}
How would you pass it in the constructor of the Controller? This isn't working :
public function __construct(){
$model = new Model();
$this->middleware('myCustomMW', $model);
}
**NOTE : ** it is important that I could pass different Models (ex. ModelX, ModelY, ModelZ)
First of all make sure that you're using Laravel 5.1. Middleware parameters weren't available in prior versions.
Now I don't believe you can pass an instantiated object as a parameter to your middleware, but (if you really need this) you can pass a model's class name and i.e. primary key if you need a specific instance.
In your middleware:
public function handle($request, Closure $next, $model, $id)
{
// Instantiate the model off of IoC and find a specific one by id
$model = app($model)->find($id);
// Do whatever you need with your model
return $next($request);
}
In your controller:
use App\User;
public function __construct()
{
$id = 1;
// Use middleware and pass a model's class name and an id
$this->middleware('myCustomMW:'.User::class.",$id");
}
With this approach you can pass whatever models you want to your middleware.
A more eloquent way of resolving this problem is to create a constructor method in the middleware, inject the model(s) as dependencies, pass them to class variables, and then utilize the class variables in the handle method.
For authority to validate my response, see app/Http/Middleware/Authenticate.php in a Laravel 5.1 installation.
For middleware MyMiddleware, model $myModel, of class MyModel, do as follows:
use App\MyModel;
class MyMiddleware
{
protected $myModel;
public function __construct(MyModel $myModel)
{
$this->myModel = $myModel;
}
public function handle($request, Closure $next)
{
$this->myModel->insert_model_method_here()
// and write your code to manipulate the model methods
return $next($request);
}
}
You don't need to pass the model to middleware, Because you already have access to model instance inside the middleware!
Lets say we have a route like this:
example.test/api/post/{post}
now in our middleware if we want to have access to that post dynamically we go like this
$post = $request->route()->parameter('post');
now we can use this $post, for example $post->id will give us the id of the post, or $post->replies will give us the replies belong to the post.

Laravel 4: Reference controller object inside filter

I have a controller in Laravel 4, with a custom variable declared within it.
class SampleController extends BaseController{
public $customVariable;
}
Two questions: Is there any way I can call within a route filter:
The controller object where the filter is running at.
The custom variable from that specific controller ($customVariable).
Thanks in advance!
as per this post:
http://forums.laravel.io/viewtopic.php?pid=47380#p47380
You can only pass parameters to filters as strings.
//routes.php
Route::get('/', ['before' => 'auth.level:1', function()
{
return View::make('hello');
}]);
and
//filters.php
Route::filter('auth.level', function($level)
{
//$level is 1
});
In controllers, it would look more like this
public function __construct(){
$this->filter('before', 'someFilter:param1,param2');
}
EDIT:
Should this not suffice to your needs, you can allways define the filter inside the controller's constructor. If you need access to the current controller ($this) and it's custom fields and you have many different classes you want to have that in, you can put the filter in BaseController's constructor and extend it in all classes you need.
class SomeFancyController extends BaseController {
protected $customVariable
/**
* Instantiate a new SomeFancyController instance.
*/
public function __construct()
{
$ctrl = $this;
$this->beforeFilter(function() use ($ctrl)
{
//
// do something with $ctrl
// do something with $ctrl->customVariable;
});
}
}
EDIT 2 :
As per your new question I realised the above example had a small error - as I forgot the closure has local scope. So it's correct now I guess.
If you declare it as static in your controller, you can call it statically from outside the controller
Controller:
class SampleController extends BaseController
{
public static $customVariable = 'test';
}
Outside your controller
echo SampleController::$customVariable
use:
public function __construct()
{
$this->beforeFilter('auth', ['controller' => $this]);
}

Resources