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.
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
So I am giving a sample of my controller and web.php file.
controller
{
public function add()
{
//Method called via web.php
}
public function multiply()
{
//how to access this while testing
}
}
web.php
route::get('/add','controller#add');
And now I want to perform unit testing
case1: add $response = $this->get(route('add')); Now it will send a get request when /add is accessed and controller method add will be accessed. And then I can use various assertions to check its functionality.
case2: multiply Here there isn't any route specified, so it wont be able to access controller method.
How can I test my multiply method in such a case
UPDATED ANSWER
So from all the answers and comments, i have understood that in Laravel
Unit Testing - Create a controller instance and then call the method that you want to test.
Feature testing - In this mode of testing, we will be calling the route and testing whether correct method has been hit and it is working as desired.
Thank You!!
You can create the object of controller inside the test file like below.
public function testBasicTest()
{
$object = (new UsersController());
$response = $object->methodName();
$this->assertTrue($response);
}
What I wanna do is to know, inside a view, if I'm in a specific controller or not. From what I know, I've got two choices and I don't have the answer to either of them :-D
inject a view variable using the share method in my AppServiceProvider, which involves getting the current controller name(or at least the action name so that I can switch it) inside the service provider.
inject a variable to all the views returned in the controller. For example does controllers have a boot method? Or can I override the view() method in the following code snippet?
public function someAction(Request $request)
{
return view('someview', ['myvar' => $myvalue]);
}
well of course there's the easy (yet not easy :|) solution: add the variable in all methods of the controller. I don't like this one.
Thanks
You could use the controller's construct function.
Add this to the top of your controller:
public function __construct()
{
view()->share('key', 'value');
}
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
}
}
All Codeigniter controllers seem to start with:
public function index()
{
// stuff
}
Is this a requirement or just good practice? I have an instance where an index may not be needed, for example I have a controller called "Auth" and in it there is a function to register and a function to login - you could argue that the login function is of higher priority but in the interest of naming convention I would rather name my functions. What is best practice here?
It's not a must method. It simply behaves like index.html on apache server.
When there is no html file specified, it automatically goes to index.html.
The same here, when there is no controller method specified index is default.
The index method is simply what's called when the second URL segment is missing. For example:
class Auth extends CI_Controller {
public function index () {
// domain.com/auth
// domain.com/auth/index
}
public function register () {
// domain.com/auth/register
}
}
If you don't need that route, you don't need an index method.