Structuring Routes in Laravel 5 - php

In my application, I have the concept of events. Each event can be booked by a user, and also unbooked if that user needs to cancel.
My event routes look like this:
Route::get('events/search', 'EventsController#search');
Route::get('events/past', 'EventsController#past');
Route::get('events/{id}/invite', [
'as' => 'invite', 'uses' => 'EventsController#invite'
]);
Route::get('events/{id}/invite/groups', [
'as' => 'inviteGroups', 'uses' => 'EventsController#inviteGroups'
]);
Route::get('events/{id}/duplicate', [
'as' => 'duplicate', 'uses' => 'EventsController#duplicate'
]);
Route::get('events/{id}/book', [
'as' => 'book', 'uses' => 'EventsController#book'
]);
Route::get('events/{id}/unbook', [
'as' => 'unbook', 'uses' => 'EventsController#unbook'
]);
Route::post('events/{id}/groups', [
'as' => 'addGroups', 'uses' => 'EventsController#addGroups'
]);
Route::post('events/{id}/helpers', [
'as' => 'addHelpers', 'uses' => 'EventsController#addHelpers'
]);
Route::resource('events', 'EventsController');
I'm having difficulty with the "book" route, which throws the following error when I hit it:
MethodNotAllowedHttpException in RouteCollection.php line 201:
The route users a function that attaches a user to an event, and then returns that user to the event page.
I'm sure its an order of precedence issue, but no matter how I organize the routes, I keep hitting that error. This is the only route on the list that's causing problems. Are there any best practices on route organization to fix this issue?

Related

Laravel 5.4 double arrow error in routes (syntax error, unexpected '=>' (T_DOUBLE_ARROW))

I used this routes for either Laravel 5.1 and Laravel 5.3, and now when I'm using this type of route order it gives me the title error hope you can help me, you can find the code here :
Route::prefix('productos')->group(function () {
'as' => 'products.index',
'uses' => 'ProductController#index'
Route::get('crear',[
'as' => 'products.create',
'uses' => 'ProductController#create'
]);
Route::post('guardar',[
'as' => 'products.store',
'uses' => 'ProductController#store'
]);
// Editar, borrar
Route::get('{id}',[
'as' => 'products.destroy',
'uses' => 'ProductController#destroy'
]);
Route::get('{id}/editar',[
'as' => 'products.edit',
'uses' => 'ProductController#edit'
]);
Route::put('{id}',[
'as' => 'products.update',
'uses' => 'ProductController#update'
]);
});
To use => you need to be in the context of an associative array in php. In your case you are using it inside a closure:
Route::prefix('productos')->group(function () {
// This section is incorrect
'as' => 'products.index',
'uses' => 'ProductController#index'
// Because is not inside an array
Route::get('crear',[
'as' => 'products.create',
'uses' => 'ProductController#create'
]);
...
If I had to guess what you are looking for something like this:
Instead of
'as' => 'products.index',
'uses' => 'ProductController#index'
You should have something like:
Route::get('listar',[
'as' => 'products.index',
'uses' => 'ProductController#index'
]);
So the endpoint would be productos/listar.
Hope this helps you.
Syntax error
'as' => 'products.index',
'uses' => 'ProductController#index'
Change it like this
Route::get('products',[
'as' => 'products.index',
'uses' => 'ProductController#index'
]);

Route not displaying the correct page

I've got 2 sections to my site, the admin side and the public side. The issue I'm having is that if I go to for example admin/menus then I go to my public side instead of going to the menus page.
I'm not sure why this is happening. I've tried to re-arrange the order of the routes in my public side but that didn't work and I've drawn a blank as to what I've done wrong.
My public routes
<?php
Route::get('/', [
'uses' => 'OpenController#index',
'as' => 'index',
]);
Route::get('/{id}', 'OpenController#content');
Route::post('/contact', [
'uses' => 'OpenController#contact',
'as' => 'contact',
]);
Route::get('/{category}/{slug}', [
'uses' => 'OpenController#productItem',
'as' => 'product.item',
]);
Route::any('/search', [
'uses' => 'OpenController#search',
'as' => 'search'
]);
my admin menus route
Route::resource('admin/menus', 'MenusController');
My productItem function
public function productItem($category, $slug)
{
$menus_child = Menu::where('menu_id', 0)->with('menusP')->get();
$contact = Contact::all();
$single_product = Product::where('slug', $slug)->get();
return view('open::public.single_item', compact('menus_child', 'contact', 'single_product'));
}
The error come in with this route
Route::get('/{category}/{slug}', [
'uses' => 'OpenController#productItem',
'as' => 'product.item',
]);
If I remove this route then it works, but I need this route so I can't remove it.
If I'm missing something else that I need to give please let me know.
This will work if u put it at the top, but it may clash with other routes i think.
Route::get('/{category}/{slug}', [
'uses' => 'OpenController#productItem',
'as' => 'product.item',
]);
you can try like this if u want
Route::get('/category/{category}/{slug}', function (\Illuminate\Http\Request $request) {
echo "ok";
});
You should prefix the route /{category}/{slug} to avoid conflicts. So replace:
Route::get('/{category}/{slug}', [
'uses' => 'OpenController#productItem',
'as' => 'product.item',
]);
By:
Route::get('/open/{category}/{slug}', [
'uses' => 'OpenController#productItem',
'as' => 'product.item',
]);
And update your links to that route in your views.
Route::get('/{category}/{slug}', [
'uses' => 'OpenController#productItem',
'as' => 'product.item',
]);
Will catch every combination of path that have two items /admin/menus, /admin/anything or /foo/bar. You are probably going to run into the same problem with
Route::get('/{id}', 'OpenController#content');
If you can not rename your routes, you need to put all the more restrictive routes on top and your less restrictive routes on the bottom.
Route::resource('admin/menus', 'MenusController');
Route::get('/', [
'uses' => 'OpenController#index',
'as' => 'index',
]);
Route::post('/contact', [
'uses' => 'OpenController#contact',
'as' => 'contact',
]);
Route::any('/search', [
'uses' => 'OpenController#search',
'as' => 'search'
]);
Route::get('/{category}/{slug}', [
'uses' => 'OpenController#productItem',
'as' => 'product.item',
]);
Route::get('/{id}', 'OpenController#content');
UPDATE
You have a few options.
Here are two of them.
You can limit what the route will accept with RegEx.
See Route Parameters > Regular Expression Constraints
Route::get('/{category}/{slug}', function () {
return 'hello';
})->where('category', '[one]*[two]*[three]*[four]*[five]*');
Or you can change the caffeine route through its config.
php artisan vendor:publish --tag=genealabs-laravel-caffeine
Then change the route in /app/config/genealabs-laravel-caffeine.php
There are some other ways as well. I'd just up a quick test site and start messing with routes to see what works the best for your needs.

Laravel 5 route groups `prefix and `as` and resource controllers

I'm using Laravel's route groups to try and stop duplication within my Routes file.
I have one main group, frontend. This has the namespace Frontend and as frontend.
Nested within that group, is another group. This group has the prefix account which appends /account/ to each route. It also has as account..
The routes inside the nested group, I'd expect to be:
frontend.account.home
frontend.account.order.show
frontend.account.order.index
Instead I get:
frontend.account.home
frontend.account.account.order.index
frontend.account.account.order.show
Code:
Route::group(['as' => 'frontend.', 'namespace' => 'Frontend'], function () {
Route::group(['prefix' => 'account', 'as' => 'account.', 'namespace' => 'Account'], function () {
Route::get('home', [
'as' => 'home',
'uses' => 'Home\Controller#get'
]);
Route::resource('order', 'Order\Controller', ['except' => [
'create',
'store',
'update',
'destroy',
'edit',
]]);
});
});
Since your excepting almost every routes from the Route::resource method, why not create 2 single routes for index and show like so:
// in your routes file, within your nested group :
Route::get('order', ['as' => 'order.index', 'uses' => 'Order\Controller#index' ]);
Route::get('order/{id}', ['as' => 'order.show', 'uses' => 'Order\Controller#show' ]);

Laravel Route pass additional variables

I have a user controller which returns users list, each user belongs to different group.
ex:- $groups = ['student_users' => 1, 'teacher_users' => 2, .....]
I can create routes such as below to access them
Route::get('users/{id}', [
'as' => 'user',
'uses' => 'Admin\UserController#listUser'
]);
But i want to create more user friendly or seo friendly say like this
Route::get('users/student', [
'as' => 'student',
'uses' => 'Admin\UserController#listUser'
]);
Route::get('users/teacher', [
'as' => 'teacher',
'uses' => 'Admin\UserController#listUser'
]);
Route::get('users', [
'as' => 'student',
'uses' => 'Admin\UserController#listUser'
]);//by default shows students list.
And i want to pass the id via route not via url. Whats the best way to do it.
do as following
Route::get('users/student', [
'as' => 'student',
'type' => 'student',
'uses' => 'Admin\UserController#listUser'
]);
in controller you can get type as below
public function listUser(\Illuminate\Http\Request $request)
$action = $request->route()->getAction();
dd($action['type']);
}
type is just an example. You can pass any variable.
I hope it helps.

How to make urls to view userprofiles like in facebook using laravel

I am creating a project in Laravel . I want to create a url
like http://www.mywebsite.com/username
so i can show the user profile based on username
so far i have this code
Route::group(array('prefix' => 'user', 'before' => 'admin'), function() {
# USer / Individual
Route::get('/', array('as' => 'user', 'uses' => 'Admin\AdminIndividualController#getindex'));
Route::get('create-user', array('as' => 'create-user', 'uses' => 'Admin\AdminIndividualController#create'));
Route::get('edit-user/{id}', array('as' => 'edit-user', 'uses' => 'Admin\AdminIndividualController#edit'))->where(array('id' => '[0-9]+'));
Route::get('delete-user/{id}', array('as' => 'del_user', 'uses' => 'Admin\AdminIndividualController#destroy'))->where(array('id' => '[0-9]+'));
Route::get('deactivate/{id}', array('as' => 'user_deactive', 'uses' => 'Admin\AdminIndividualController#deactive_user'))->where(array('id' => '[0-9]+'));
Route::get('active/{id}', array('as' => 'user_active', 'uses' => 'Admin\AdminIndividualController#active_user'))->where(array('id' => '[0-9]+'));
Route::post('create-user', array('as' => 'post-user', 'uses' => 'Admin\AdminIndividualController#store'));
Route::post('update-user/{id}', array('as' => 'update-user', 'uses' => 'Admin\AdminIndividualController#update'))->where(array('id' => '[0-9]+'));
# USer [Individual] Skills
Route::get('create-skill', array('as' => 'create-user-skill', 'uses' => 'Admin\AdminIndividualController#create_skill'));
Route::get('delete-skill/{id}', array('as' => 'del_skill', 'uses' => 'Admin\AdminIndividualController#destroy_skill'))->where(array('id' => '[0-9]+'));
Route::post('create-skill', array('as' => 'create-user-skill', 'uses' => 'Admin\AdminIndividualController#store_skill'));
#send email to user
Route::get('send-email/{id}', array('as' => 'create-email-user', 'uses' => 'Admin\AdminIndividualController#create_email'))->where(array('id' => '[0-9]+'));
Route::post('send-email', array('as' => 'send-email-user', 'uses' => 'Admin\AdminIndividualController#send_email'));
});
I couldnt find any way to create routing for that if i create just a simple route it disturbs all my other urls like /logout
After Brainstorming here is what i concluded i have to implement it in order to check if this works or not
Route::filter('user.item', function($route, $request)
{
if ($route->parameter('item')->user_id !== Auth::user()->id)
{
App::abort(404);
}
});
What ill be doing is applying filter to routes to check from database if that username exists or not if it does exist ill fetch the view for profile and show the profile otherwise run the url as it is .Is it possible that way >?
A route that has a dynamic segment in the first place should be put after all the other routes so it only runs when the other routes don't match...
Route::get('foo', ...);
Route::get('bar', ...);
Route::get('{user}', ...);
Note that there is still a problem because a user can't have the name create-user because otherwise he won't see his profile but rather the actual create-user route.
That means if you really want to have the profile URL like that you should validate the username and check for reserved words (which are actually your other routes)
Of course the alternative is to just use something like user/{username}
You are right that such routing will overload all other routes and nothing works.
It is much easier to create url like http://www.mywebsite.com/u/username
If you want to have route /{username} then you can either make all other urls to be made of 2 or more url segments or make ineffective manual magic in the routing.
In manual routing you can see if the username matches any user and if not then perform the logout for example. You also need to keep in mind that someones username can be logout.
Bind your username "key" (in your route) and create a Route Bind.
Route::bind('username',function($value){
return User::where('username',$value)->first();
});
Route::group(array('prefix' => '{username}', 'before' => 'admin'), function() {
# USer / Individual
Route::get('/', array('as' => 'user', 'uses' => 'Admin\AdminIndividualController#getindex'));
Route::get('create-user', array('as' => 'create-user', 'uses' => 'Admin\AdminIndividualController#create'));
Route::get('edit-user/{id}', array('as' => 'edit-user', 'uses' => 'Admin\AdminIndividualController#edit'))->where(array('id' => '[0-9]+'));
Route::get('delete-user/{id}', array('as' => 'del_user', 'uses' => 'Admin\AdminIndividualController#destroy'))->where(array('id' => '[0-9]+'));
Route::get('deactivate/{id}', array('as' => 'user_deactive', 'uses' => 'Admin\AdminIndividualController#deactive_user'))->where(array('id' => '[0-9]+'));
Route::get('active/{id}', array('as' => 'user_active', 'uses' => 'Admin\AdminIndividualController#active_user'))->where(array('id' => '[0-9]+'));
Route::post('create-user', array('as' => 'post-user', 'uses' => 'Admin\AdminIndividualController#store'));
Route::post('update-user/{id}', array('as' => 'update-user', 'uses' => 'Admin\AdminIndividualController#update'))->where(array('id' => '[0-9]+'));
# USer [Individual] Skills
Route::get('create-skill', array('as' => 'create-user-skill', 'uses' => 'Admin\AdminIndividualController#create_skill'));
Route::get('delete-skill/{id}', array('as' => 'del_skill', 'uses' => 'Admin\AdminIndividualController#destroy_skill'))->where(array('id' => '[0-9]+'));
Route::post('create-skill', array('as' => 'create-user-skill', 'uses' => 'Admin\AdminIndividualController#store_skill'));
#send email to user
Route::get('send-email/{id}', array('as' => 'create-email-user', 'uses' => 'Admin\AdminIndividualController#create_email'))->where(array('id' => '[0-9]+'));
Route::post('send-email', array('as' => 'send-email-user', 'uses' => 'Admin\AdminIndividualController#send_email'));
});
If its ok for you to display URL of the user's profile page like this: http://website.com/#username then you can show the user's profile based on his username like this:
in routes.php file
Route::get("#{username}", array(
"as" => "users.show",
"uses" => "UsersController#show",
));
in UsersController.php file
public function show($username)
{
$user = User::where("username", "=", $username)->first();
if (is_null($user))
{
return App::abort(404);
}
return View::make("path/to/view/file")->with("user", $user);
}
and you can create links with that URL http://website.com/#username like this:
{{ $user->username }}
this way you don't need to check for reserved words (which are your other routes) unless you already have a route begins with the symbol #.

Categories