I am new to Laravel 4 and am having a hard time grasping routes. I have a frontend to my site and a backend. All the stuff that happens on the backend I want to have displayed under example.com/dashboard/.... I also want to use resourceful controllers. What do I need to setup in routes.php to have it so I can always refer to my users controller but have it all happen under dashboard in the URL?
Example:
I link to users/edit/1 but in the URL looks like example.com/dashboard/users/edit/1. Dashboard should have an index page (so example.com/dashboard actually shows a page) but all other URLs are appended to that.
I think this is covered pretty well in the Larvel 4 Documentation.
Unless I'm misunderstanding, this should get you the desired results for your example case:
Route::get('dashboard', 'DashboardController#index');
Route::get('dashboard/users/edit/{id}', 'UsersController#edit');
etc.
// edit
Alternatively, using a Closure callback, you could do something like this:
Route::get('dashboard/users/{var1}/{var2?}', function($var1, $var2 = null)
{
$controller = new UsersController;
return $controller->{$var1}($var2);
});
Which wouldn't require you to specify each and every route. Or, as I mentioned below in comments, you could use a Resource Controller if it suits your needs.
Related
I am creating APIs for an app. Now app developer wants me to create a fixed base url and pass the ROUTE NAME (Which will point to controller function) as POST variable. Example:
http://example.com/Api
and POST variables like:
action=>'ROUTE_NAME'
But in laravel we can define the routes based upon the url parts as:
http://example.com/Api/ROUTE_NAME
I have tried using a single controller and loading the other controllers based upon SWITCH statements. But that doesn't seem to be a standard practice as i need to add switch condition every time I'll create a new API. Also middleware will not work on the loaded controllers dynamically.
Is there a way in laravel to achieve this? I am using laravel 5.4
You could implement a middleware that listens on the /Api route, which gets the ROUTE_NAME from the $request, then you could use the Route() helper function to find the url of that named route, then redirect the request to that route.
Something like:
// Generating ROUTE_NAME url...
$url = route($request->route_name);
// Redirect to that route...
return redirect()->route($url);
Obviously you'll need to add code to handle if it doesn't find a route etc, maybe return a json response back with a proper error code etc.
I have a user RESTful resource route in my Laravel App.
Route::resource('backbone.users', 'backbone\UserController');
for the the CRUD operations.
Unfortunately, I get following URIs:
I get {backbone} in the URI that results in %backbone% in the browser but
I want the URL like dev.domain/backbone/users NOT dev.domain/backbone/%backbone%/users
I would need to redirect like:
return Redirect::intended('backbone/{backbone}/users');
How come?
It's hard to tell by the screenshot (or maybe my eyes aren't great) but it looks like backbone/{backbone}/users. If this is the case, that's intended, the {} are indicating that it can take a variable in this position.
So it might be return Redirect::intended('background/1/users');
The controller method to go with it, in this case index of UserController will receive that variable as its argument.
This is normal for Laravel. The {} in your routes list represent url variables.
Take this route for example:
/users/{user}/edit
To use this route you would navigate to
/users/1/edit
Assuming you have your controller method setup similar to:
public function edit($userId)
{
}
The $userId variable would contain '1' from the url. Definitely checkout the docs for more on Laravel routing
As I am new to the laravel 4 after spending some few months in Codeigniter, I went through the lots of tutorials about laravel and one thing I want to be clear is what is the actual difference between Routes and Controller in laravel, because we can create and generate view in both controller and routes too. Will anyone explain me in brief when to use routes and Controller in laravel? Because in other Framework we need routes to specify some particular URL's within the apps and Controller were used to do some real tasks but in laravel I didnt get the main concept of Routes except the routing mechanism?
In Laravel, you can totally skip controllers and do the task of performing business logic and generating the view in the routes.
E.g I have a link b2.com/getUsers so in routes.php I can write:
Route::get('/getUsers',function()
{
$users=User::all(); //select * from users
return View::make('allUsers')->with('users',$users);
}
So, here to serve the request b2.com/getUsers, we didn't use controller at all and you can very well do this for handling all requests in your application, both get and post.
But then, if your application is large and have 500+ url's with complex business logic then imagine putting everything in one routes.php. It will totally make it criminally messy and whole purpose of architecture will be defeated. Hence what we usually do is, reserve routes.php for routing only and write all business logic (along with generation of views inside controllers)
So the same example can be solved as:
To handle link: b2.com/getUsers, in routes.php
Route::get('/getUsers', array('before' => 'auth', 'uses' => 'MyController#getUsers'));
MyController has the method getUsers defined like this:
public function getUsers()
{
$users=User::all(); //select * from users
return View::make('allUsers')->with('users',$users);
}
I usually create a controller for related activities e.g for login/signup/logout. I create AuthController and all the links related to those activities are routed to AuthController through routes.php.
The fact that you can get views or do a lot of things in Routes::any() is against MVC and separation of logic.
In Route::get("admin", function(){}), you indeed have a fast access to your route callback, which otherwise in a standard fashion must just be bound to controller. But Laravel allows you to do your job there in a closure (function(){}), instead of binding it to a controller. Anyway, it lets you, but you'd better avoid it. In Route::get() you only should go with your 'routing' and nothing more.
There is no reason for you to use callbacks in Route unless for testing or some trivial requests. So, better to avoid this:
Route::get("admin", function(){
return View::make("admin_index");
});
And rather go with this:
Route::controller("admin", "AdminController");
And in your AdminController.php :
// I mean create a file named AdminController.php in controllers directory under app.
class AdminController extends Controller
{
function getIndex()
{
return View::make("admin_index");
}
}
Read more about Route::controller and restful controllers.
Some Notes:
Having the ability to add closures in your Routes allows you to make
complex decisions on Routes and have a powerful routing system.
These callbacks let you add conditions to your route.
Having Controller separated from you Routes makes you application
more extensible, less confusing and makes other coders more
comfortable in future.
It allows you to focus better on your problem and finding solution,
this physical separation is very important. Having View::make()
inside your Route stirs all problems into each other and makes up a
confusion for the coder.
Let's see what we have in both cases:
In CodeIgniter, a route is just pointing your request to a specific method of your controller:
$route['blog/joe'] = "blogs/users/34";
Here when you visit application.com/blog/joe, you will invoke the controller BlogsController, call the method users() and pass 34 as the first parameter. Nothing else. As they put it, a route in CI is just a one-to-one relationship between a URL string and its corresponding controller class/method.
Now, in Laravel, you have a lot of possibilities:
You can directly return a simple response
You can return a view
You can point the request to a specific controller and a method
You can write some logic in a closure and then decide what you want to do
You can add some additional functionality to them, like attaching filters, checking parameters upon a regex, give them separate names, etc., but this is the main functionality.
What's the reason for being able to do so much stuff? It gives you the power to use them in any way you need. Examples:
Need a small website, rendering static HTML? Use them like this:
Route::get('/', function()
{
return View::make('greeting');
});
Need a bigger application using the traditional MVC pattern? Use like this:
Route::get('user/{id}', 'UserController#showProfile');
Need a RESTful approach? No problem. This will generate routes for all the CRUD methods:
Route::resource('photo', 'PhotoController');
Need something quick and dirty to handle a specific Ajax request? Keep it simple:
Route::post('foo/bar', function()
{
return 'Hello World';
});
TL;DR: For very simple things without or with very little logic, use them instead of controllers. Otherwise, always stick to the MVC principles and route to your controllers, so that they're the ones who do the actual work.
Laravel routing functionality allows you to name a resource and name a controller to go with it. I am new to Laravel and would like to know if anyone knows how to extend the resources method in the route class provided.
Basically say I have: (which works fine)
/invoices
But say I want:
/invoices/status/unpaid
How is this achievable?
To see the basics of what I am doing check:
http://laravel.com/docs/controllers#resource-controllers
Resource controllers tie you into a specific URLs, such as:
GET|POST /invoices
GET|PUT /invoices/{$id}
GET /invoices/create
and so on as documented.
Since, by convention, GET /invoices is used to list all invoices, you may want to add some filtering on that:
/invoices?status=unpaid - which you can then use in code
<?php
class InvoiceController extends BaseController {
public function index()
{
$status = Input::get('status');
// Continue with logic, pagination, etc
}
}
If you don't want to use filtering via a query string, in your case, you may be able to do something like:
// routes.php
Route::group(array('prefix' => 'invoice'), function()
{
Route::get('status/unpaid', 'InvoiceController#filter');
});
Route::resource('invoice', 'InvoiceController');
That might work as the order routes are created matter. The first route that matches will be the one used to fulfill the request.
There will be several high profile links for customers to focus on, for example:
Contact Us # domain.com/home/contact
About the Service # domain.com/home/service
Pricing # domain.com/home/pricing
How It Works # domain.com/home/how_it_works
Stuff like that. I would like to hide the home controller from the URL so the customer only sees /contact/, not /home/contact/. Same with /pricing/ not /home/pricing/
I know I can setup a controller or a route for each special page, but they will look the same except for content I want to pull from the database, and I would rather keep my code DRY.
I setup the following routes:
Route::get('/about_us', 'home#about_us');
Route::get('/featured_locations', 'home#featured_locations');
Which work well, but I am afraid of SEO trouble if I have duplicate content on the link with the controller in the URL. ( I don't plan on using both, but I have been known to do dumber things.)
So then made routes like these:
Route::get('/about_us', 'home#about_us');
Route::get('/home/about_us', function()
{
return Redirect::to('/about_us', 301);
});
Route::get('/featured_locations', 'home#featured_locations');
Route::get('/home/featured_locations', function()
{
return Redirect::to('/featured_locations', 301);
});
And now I have a redirect. It feels dumb, but it appears to be working the way I want. If I load the page at my shorter URL, it loads my content. If I try to visit the longer URL I get redirected.
It is only for about 8 or 9 special links, so I can easily manage the routes, but I feel there must be a smart way to do it.
Is this even an PHP problem, or is this an .htaccess / web.config problem?
What hell have I created with this redirection scheme. How do smart people do it? I have been searching for two hours but I cannot find a term to describe what I am doing.
Is there something built into laravel 4 that handles this?
UPDATE:
Here is my attempt to implement one of the answers. This is NOT working and I don't know what I am doing wrong.
application/routes.php
Route::controller('home');
Route::controller('Home_Controller', '/');
(you can see the edit history if you really want to look at some broken code)
And now domain.com/AboutYou and domain.com/aboutUs are returning 404. But the domain.com/home/AboutYou and domain.com/home/aboutUs are still returning as they should.
FINAL EDIT
I copied an idea from the PongoCMS routes.php (which is based on Laravel 3) and I see they used filters to get any URI segment and try to create a CMS page.
See my answer below using route filters. This new way doesn't require that I register every special route (good) but does give up redirects to the canonical (bad)
Put this in routes.php:
Route::controller('HomeController', '/');
This is telling you HomeController to route to the root of the website. Then, from your HomeController you can access any of the functions from there. Just make sure you prefix it with the correct verb. And keep in mind that laravel follows PSR-0 and PSR-1 standards, so methods are camelCased. So you'll have something like:
domain.com/aboutUs
In the HomeController:
<?php
class HomeController extends BaseController
{
public function getAboutUs()
{
return View::make('home.aboutus');
}
}
I used routes.php and filters to do it. I copied the idea from the nice looking PongoCMS
https://github.com/redbaron76/PongoCMS-Laravel-cms-bundle/blob/master/routes.php
application/routes.php
// automatically route all the items in the home controller
Route::controller('home');
// this is my last route, so it is a catch all. filter it
Route::get('(.*)', array('as' => 'layouts.locations', 'before' => 'checkWithHome', function() {}));
Route::filter('checkWithHome', function()
{
// if the view isn't a route already, then see if it is a view on the
// home controller. If not, then 404
$response = Controller::call('home#' . URI::segment(1));
if ( ! $response )
{
//didn't find it
return Response::error('404');
}
else
{
return $response;
}
});
They main problem I see is that the filter basically loads all the successful pages twice. I didn't see a method in the documentation that would detect if a page exists. I could probably write a library to do it.
Of course, with this final version, if I did find something I can just dump it on the page and stop processing the route. This way I only load all the resources once.
applicaiton/controllers/home.php
public function get_aboutUs()
{
$this->view_data['page_title'] = 'About Us';
$this->view_data['page_content'] = 'About Us';
$this->layout->nest('content', 'home.simplepage', $this->view_data);
}
public function get_featured_locations()
{
$this->view_data['page_title'] = 'Featured Locations';
$this->view_data['page_content'] = 'Featured properties shown here in a pretty row';
$this->layout->nest('content', 'home.simplepage', $this->view_data);
}
public function get_AboutYou()
{
//works when I return a view as use a layout
return View::make('home.index');
}