I just started working with Laravel after CodeIgniter and there some things that just confuse me.
I have a PagesController which takes care of displaying static pages such as about, contact, privacy etc'.
Now, instead of creating 3-4 methods on my PagesController, I would like to create one method thats called ShowPage($which) { } and knows which page to display.
The thing is > I can't understand the route issue:
Route::get('about','PagesController#ShowPage'); <--- I need to pass 'about' here
Route::get('contact','PagesController#ShowPage');
Route::get('about','PagesController#ShowPage');
Is that possible or should I need to create a method for each one of these cases?
Here is my exact code:
Controller:
class PagesController extends BaseController {
function showPage($which) {
echo $which;
}
}
Routes:
Route::get('about','PagesController#showPage');
Route::get('contact','PagesController#showPage');
Route::get('about','PagesController#showPage');`
You can access the route directly inside your controller by using
switch(Request::path()){}
which resolves to about, contact etc.
Another way to go about it would be to use
Route::get('{page}', 'PagesController#ShowPage');
which will pass the variable in the controller like
public function showPage($page){}
but be aware that this route will match any path,
if there is not another match above it.
They're already being passed down to the method:
public function ShowPage($which){
switch($which){
case 'about':
// do something
break;
case 'contact':
// do something else
break;
default:
break;
}
}
You may try this:
// In your routes.php (This route will match only this route because of "where")
Route::get('{page}','PagesController#showPage')->where('page', 'about|contact');
If you use http://example.com/about (or contact) it'll work but with other values it won't work, in other words, this route won't match without about or contact.
Then in your controller, try this:
class PagesController extends BaseController {
public function showPage($page) {
// use $page, don't use use switch, $page will be either about or contact
}
}
Related
I have been declaring all the routes for my application inside web.php , but it is now getting quite large. I find that I am losing a lot of time shifting between web.php and each controller and this is hurting productivity.
I feel like it would be better to define routes inside of the controller, perhaps ideally delegating some URL to a controller and then allowing the controller to handle the "sub routes" since this would allow me to use inheritance when I have two similar controllers with similar routes.
It is not possible given how laravel works. Every request is passed onto router to find its designated spot viz. the controller with the method. If it fails to find the route within the router, it just throws the exception. So the request never reaches any controller if the route is not found. It was possible in earlier versions on Symphony where you would configure the route in the comment of a particular controller method.
Sadly with laravel it works how it works.
But for me, I just like to have the routes in a separate file.
Alternate solution, easier way to sort all the routes.
You can move your route registration into controllers if you use static methods for this. The code below is checked in Laravel 7
In web.php
use App\Http\Controllers\MyController;
.....
MyController::registerRoutes('myprefix');
In MyController.php
(I use here additional static methods from the ancestor controller also posted below)
use Illuminate\Support\Facades\Route;
.....
class MyController extends Controller {
......
static public function registerRoutes($prefix)
{
Route::group(['prefix' => $prefix], function () {
Route::any("/foo/{$id}", self::selfRouteName("fooAction"));
Route::resource($prefix, self::selfQualifiedPath());
}
public function fooAction($id)
{
........
}
In Controller.php
class Controller extends BaseController {
....
protected static function selfAction($actionName, $parameters = [], $absolute = false)
{
return action([static::class, $actionName], $parameters, $absolute);
}
protected static function selfQualifiedPath()
{
return "\\".static::class;
}
protected static function selfRouteName($actionName)
{
//classic string syntax return "\\".static::class."#".$actionName;
// using tuple syntax for clarity
return [static::class, $actionName];
}
}
selfAction mentioned here is not related to your question, but mentioned just because it allows making correct urls for actions either by controller itself or any class using it. This approach helps making action-related activity closer to the controller and avoiding manual url-making. I even prefer making specific functions per action, so for example for fooAction
static public function fooActionUrl($id)
{
return self::selfAction('foo', ['id' => $id]);
}
Passing prefix into registerRoutes makes controller even portable in a sense, so allows inserting it into another site with a different prefix in case of conflict
I am trying to pass a parameter to my UserController but i can't seem to find a method to do this. All other topics give examples where the parameter is already defined in the url but that is not what i want.
$my_var = "some data";
Route::get('/login', 'Auth\UserController#login');
I need $my_var in my UserController
class UserController extends Controller
{
public function login()
{
// Retreive $my_var somehow
return view("login");
}
}
Sorry for my bad english, it's not my native language
In some cases using hardcoded parameters might be reasonable way to go, and one such could be case where you need to get different kinds of entities from single controller.
For an example you could have restful "users/" -route, which fetches all users from UserModel. Next you wish to separate "normal" users and admin-users by having "admin-users/" -route. Now one way to go is to represent both routes to web.php, and make them point to same controller:
Route::resource('users', 'UserController');
Route::resource('admin-users', 'UserController');
One way to solve this separation is by not passing an argument, but by detecting which route was called:
$sqlFilters['user_is_admin'] = $request->is('admin-users') || $request->is('admin-users/*');
This checks whether controller was accessed via "admin-users". Asterisk is wildcard for any route under "admin-users" path.
This method has been existing at least since Laravel 6.0, probably even before that: https://laravel.com/docs/8.x/requests#inspecting-the-request-path
You are doing it wrong. That's not how you work with an MVC framework and it's better not to define a variable or constant in web.php which is for your routes and middlewares only. By the way, if you need to do it this way, you have two ways:
1) Use a trait:
web.php:
trait TestTrait {
public static $my_var = 'some data';
}
Route::get(/login', 'Auth\UserController#login');
UserConroller.php:
use TestTrait;
class UserController extends Controller
{
use TestTrait;
public function login()
{
// You can retrieve it as a variable: $my_var
echo TestTrait::$my_var;
}
}
2) Use a constant instead of a variable:
web.php:
define('MY_VAR', 'some data');
Route::get('/login', 'Auth\UserController#login');
UserConroller.php:
public function login()
{
// You can retrieve it as a constant: MY_VAR
echo MY_VAR;
}
If the variable is hardcoded, why not state it as a constant?
If no other logic is needed, the variable can be passed through the routes file.
$my_var = "some data";
Route::get('/login', function(){
Return view('login', compact('my_var')):
});
I have a controller with the "getUsers" function in a controller called "UserController" , and inside it I want to call a function of the "CarController" controller called "getCars", the two options I have are:
a) Make the second call as "static" , then I can call it without instantiating the class
b) Do not do that function of the static class and I call it in this way
$ car_id = 100;
$ userController = new UserController ();
$ userController-> getCars ($ car_id);
I do not know which is the best practice, or what pros or cons has one or another.
I'm using laravel.
Thanxs.
It is a bad practice to call a controller from another controller, this usually signals that you have badly designed your code and you should think of a different way to achieve what you want.
None the less, you can do it like this:
app()->call('App\Http\Controllers\CarController#getCars');
If your controller method has parameters you can pass them as the second argument:
app()->call('App\Http\Controllers\CarController#getCars', [$param1, $param2]);
To answer your question, you should not call one controller method from another. As #elfu mentioned, this is not the intended functionality of a controller anyway. His post is correct and in your case you should probably use the User model as the location of this method, but I thought I'd at to it a little.
If you do want to share methods between multiple controllers, a good place to do this is through a Trait. In some cases, you are not referencing a model that is shared between controllers, and a Trait would be your best option.
To include a trait, you can reference it by including it at the top of your controller and then with a 'use' statement after the class declaration for the controller. Here is an example:
use App\Traits\ExampleTrait;
class CarController extends Controller
{
use ExampleTrait;
...
You would do the same in the UserController. Then, any method that you place in the ExampleTrait will be directly accessible from the CarController and the UserController by referencing it as $this->methodName(), just like referencing any other method in the same controller.
In your particular case, I would say that your logic should probably be stored in the User model, since the cars for a user are really an ATTRIBUTE of the User model, but the above gives you another option to work with.
In my humble opinion you should not call another controller in a controller.
It looks like you have some business logic in that controller. So you should move your logic to the entity (User.php) and call it in both controllers methods.
A regular controller returns a view (at least that is what is expected), so if you want to call another controller you should just send that route to that method (in web.php file) instead of calling it in another controller.
Hope that helps you.
You can call one controller function from another but the best way is to create a trait and use it both the controllers like:
trait Common
{
public function method(){}
}
class FirstController extends Controller
{
use Common;
}
class SecondController extends Controller
{
use Common;
}
If you want to bind parameters to the call, you can use:
$videos = app()->call('App\Http\Controllers\StorageController#returnViewVideo',[
'course'=>$course,
'lesson'=>$lesson,
]);
The following code worked for me well. and also it also can be used in routes.php
public function mobileImageUpload(Request $request){
$this->validate($request,[
'data'=>'required',
'filetype'=>'required',
'userid'=>'required',
]);
$namespace = 'App\Http\Controllers';
$controller = app()->make($namespace.'\ImageController');
return $controller->callAction('mobileImageUpload',[$request]);
}
Hi guys I hope someone can help me, I'm using laravel 4 and I have a REST controller like this
Route::controller('example', 'SomeClass');
class SomeClass extends BaseController {
public function getThisIsATest() {
return 'Hello World';
}
}
but when I try to enter the URI localhost/example/this-is-a-test
I get a 'Controller method not found.'
I'm thinking it's because the two consecutive uppercase letters in the 'getThisIsATest'
Does someone know how to fix this issue??
Two ways (without changing the URL)...
1. Use an additional route
Add an implicit route for the URL before the controller route:
Route::get('example/this-is-a-test', 'SomeClass#getThisIsATest');
Route::controller('example', 'SomeClass');
2. Change your method name to snake_case
You can change the method name in your controller to snake case and everything will work as excepted. (It doesn't look very pretty though)
public function get_this_is_a_test() {
return 'Hello World';
}
Actually it even works to only write the "problematic" part in snake case: getThisIsA_test. However this looks even more weird ;)
Try this:
Route::resource('example/this-is-a-test', 'SomeClassController#getThisIsATest');
OR:
Route::get('example/this-is-a-test', 'SomeClassController#getThisIsATest');
See, if that solves your problem & Do visit Laravel Controller Docs for more information
Add {{ URL::to('example/this-is-a-test'); }} and you're good to go
In your app/routes.php try defining your route as follows:
Route::controller("example", "testController");
And rename your controller class to
class testController extends BaseController {
public function index(){
// Just have it here to be safe.
}
public function getTest() {
return 'Hello World';
}
}
Now try navigating to localhost/example/test. Let me know if that works, I've never used Route::controller() before, so it's new to me as well.
Edit
As the above doesn't work for this example, try navigating to localhost/example/this-is-atest without changing your controller/route.
I have a laravel resource controller as follow:
BlogController.php
class AdminBlogController extends BaseController {
public function index()
{
// some code
}
public function create()
{
// some code
}
// etc.....
in route.php I have this :
Route::resource('blog', 'AdminBlogController');
now I understand that when you go to URL /blog , it goes to index() and when you go to /blog/create goes to create() method.
My question is how do I handle missing method? for example when some types /blog/test , I get an error there , how can I redirect back missing methods to /blog?
Thanks
Taken from the Laravel Documentation:
If you are using resource controllers, you should define a __call
magic method on the controller to handle any missing methods.
In your AdminBlogController, add a __call magic method:
public function __call($method,$parameters = array())
{
if (!is_numeric($parameters[0])) {
return Redirect::to('blog');
}
else {
$this->myShow($parameters[0]);
}
}
...and, importantly, you need to rename your show method to something else (myShow in this example). Otherwise, /blog/test will route to show with the expectation that test is an id of a blog that you want to show. You also need to specify, in your __call method, which parameters after blog/ should be considered IDs, and which should be considered missing methods. In this example, I allow any numeric parameter to be treated as an ID, while non-numeric parameters will redirect to Index.