getting user profile using a slug - laravel-5

I am trying to retrieve a user profile using a unique slug. With the user signed in, I can only get the first profile recorded in the db instead of the signed in user, and I am not sure why? I still wanna be able to see the profiles if I am not signed in.
The address bar should read
.app:8000/profile/signedinsuer , or selected user
instead it always reads
.app:8000/profile/firstuser .
I can manually change the address bar, and the rest works as it should, I get the right view etc. I'm just not getting the right slug through.
Route
Route::group(['prefix' => '/profile'], function () {
Route::get('/{profile}', 'Profile\ProfileController#index')->name('profile.index');
Controller
class ProfileController extends Controller
{
public function index(Profile $profile)
{
return view('overview.profile.index', [
'profile' => $profile,
]);
}
}
From Blade
<li>
Profile
</li>
Composer
class ProfileComposer
{
public function compose(View $view)
{
if (!Auth::check()) {
return;
}
$view->with('profile', Auth::user()->profile->first());
}
}

You can customize the query logic for route model binding in the RouteServiceProvider:
public function boot()
{
parent::boot();
Route::bind('profile', function ($value) {
return App\User::where('profile', $value)->first() ?? abort(404);
});
}

Related

Laravel authorization policy not working on Show page

I have a laravel app using Policies to assign roles and permissions, i cant seem to access the show page and im not sure what im doing wrong?
If i set return true it still shows a 403 error as well, so im unsure where im going wrong here. The index page is accessable but the show page is not?
UserPolicy
public function viewAny(User $user)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
public function view(User $user, User $model)
{
if ($user->isSuperAdmin() || $user->hasPermissionTo(44, 'web')) {
return true;
}
return false;
}
UserController
public function __construct()
{
$this->authorizeResource(User::class, 'user');
}
public function index()
{
$page_title = 'Users';
$page_description = 'User Profiles';
$users = User::all();
return view('pages.users.users.index', compact('page_title', 'page_description', 'users'));
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
$user = User::findOrFail($id);
$user_roles = $user->getRoleNames()->toArray();
return view('pages.users.users.show', compact('user', 'user_roles'));
}
Base on Authorize Resource and Resource Controller documentation.
You should run php artisan make:policy UserPolicy --model=User. This allows the policy to navigate within the model.
When you use the authorizeResource() function you should implement your condition in the middleware like:
// For Index
Route::get('/users', [UserController::class, 'index'])->middleware('can:viewAny,user');
// For View
Route::get('/users/{user}', [UserController::class, 'view'])->middleware('can:view,user');
or you can also use one policy for both view and index on your controller.
I had an issue with authorizeResource function.
I stuck on failed auth policy error:
This action is unauthorized.
The problem was that I named controller resource/request param with different name than its model class name.
F. ex. my model class name is Acknowledge , but I named param as timelineAcknowledge
Laravel writes in its documentation that
The authorizeResource method accepts the model's class name as its first argument, and the name of the route / request parameter that will contain the model's ID as its second argument
So the second argument had to be request parameter name.
// Here request param name is timelineAcknowledge
public function show(Acknowledge $timelineAcknowledge)
{
return $timelineAcknowledge->toArray();
}
// So I used this naming here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'timelineAcknowledge');
}
Solution was to name request param to the same name as its model class name.
Fixed code example
// I changed param name to the same as its model name
public function show(Acknowledge $acknowledge)
{
return $acknowledge->toArray();
}
// Changed here also
public function __construct()
{
$this->authorizeResource(Acknowledge::class, 'acknowledge');
}
I looked over Laravel policy auth code and I saw that the code actually expects the name to be as the model class name, but I couldn't find it anywhere mentioned in Laravel docs.
Of course in most of the cases request param name is the same as model class name, but I had a different case.
Hope it might help for someone.

Perform post route controller logic after login only when specific button is clicked without just getting redirected towards original page in Laravel

How to perform post route action after successfully authenticating user. Consider i have a post route which adds products to wish-list on clicking the wish-list button. But the controller contains an auth middleware, so when a user is not logged in and clicks on the wish-list button, he/she is redirected towards the login route. Currently after logging in my user is getting redirected towards the product listing page. but i want it to perform the addition of product logic inside my controller after login and then redirect to the necessary page as mentioned in controller. I have provided my code below:
ProductController
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct() {
$this->middleware('auth')->only('addToWishList');
}
public function addToWishList($productId) {
// Checking if product exist in wish list
if (User::checkUserProductCount(auth()->user()->id, $productId, 1) > 0) return redirect()->route('userWishlist')
->with('success', 'Product already present in wish-list');
// adding the product
User::addProductToUserWishList(User::getUserById(auth()->user()->id), $productId);
return redirect()
->route('userWishlist')
->with('success', 'Product has been added to wish-list');
}
UserController
public static function checkUserProductCount($userId, $productId, $type) {
return count(self::getUserProduct($userId, $productId, $type));
}
public static function getUserProduct($userId, $productId, $type) {
return DB::table('product_user')
->where('user_id', $userId)
->where('product_id', $productId)
->where('type', $type)
->get();
}
public static function addProductToUserWishList($userCollection, $productId) {
$userCollection
->products()->attach([
$productId => [
'type' => 1 // 1 is wish list here
]
]);
}
public static function getUserById($userId) {
return User::where('id', $userId)
->firstOrFail();
}

Multiple update methods in same controller Laravel 6

I am currently trying to build a user registration system with edit fields. At the edit portion, I had to create separate views for editing/updating personal details, email, and passwords.
I started with an empty resource controller. it had only one edit method. Hence I added additional edit methods. Each method can have a separate route. However, I have a hard time having a separate route for each update method in each section as the resource has only one route like this in docs:
PUT/PATCH /photos/{photo} update photos.update
Is there any workaround for this?
Controller
class UserController extends Controller
{
public function __construct()
{
$this->middleware(['auth', 'verified']);
}
public function index()
{
return view('users.index');
}
public function edit_personal(User $user)
{
$user_profile = User::find($user->id);
return view('users.edit.personal', ['users' => $user_profile]);
}
public function update_personal(Request $request, User $user)
{
// How to write route for this method.
}
public function edit_email(User $user)
{
$user_profile = User::find($user->id);
return view('users.edit.email', ['users' => $user_profile]);
}
public function update_email(Request $request, User $user)
{
// How to write route for this method.
}
public function edit_password(User $user)
{
$user_profile = User::find($user->id);
return view('users.edit.password', ['users' => $user_profile]);
}
}
Routes
Auth::routes(['verify' => true]);
Route::get('/', function () {
return view('welcome');
});
Route::get('/users/{user}/personal', 'UserController#edit_personal')->name('users.personal');
Route::get('/users/{user}/email', 'UserController#edit_email')->name('users.email');
Route::get('/users/{user}/password', 'UserController#edit_password')->name('users.password');
Route::resource('users', 'UserController');
Basically I have separated edit portion of user controller into personal, email and password sections and they have separate forms. I want to write update functions for each section in UserController.
don't know why are you using separate forms for updating each fields while you can do it in a single form. however you can use either put/patch or post method for updates. here's i am using post for example.
routes:
Route::get('users/{user}/personal', 'UserController#edit_personal')->name('users.personal');
Route::post('users/{user}/personal', 'UserController#update_personal')->name('users.update-personal');
Route::get('users/{user}/email', 'UserController#edit_email')->name('users.email');
Route::post('users/{user}/email', 'UserController#update_email')->name('users.update-email');
Route::get('users/{user}/password', 'UserController#edit_password')->name('users.password');
Route::post('users/{user}/password', 'UserController#update_password')->name('users.update-password');
as you are using route model binding you can directly get the object.
public function edit_personal(User $user)
{
return view('users.edit.personal', ['users' => $user]);
}
public function update_personal(Request $request, User $user)
{
//validation goes here
$user->update([
'value' => $request->value,
...........
]);
}

Getting error in Laravel 5.7 edit route page not found

Laravel Version 5.7
PHP 7+
I created a resource controller -> CategoryController [having all the magic methods]
This is the routes/web.php
Route::group(['as'=>'admin.','middleware'=>['auth','admin'],'prefix'=>'admin'], function(){
Route::get('/dashboard','AdminController#dashboard')->name('dashboard');
// product resource controller methods
// check php artisan r:l
Route::resource('product', 'ProductController');
Route::resource('category', 'CategoryController');
Route::resource('profile', 'ProfileController');
Route::post('remove', 'CategoryController#remove')->name('category.remove');
});
Now as you can see, I have "http://127.0.0.1:8000/admin/category/1/edit" for one of my categories to edit with category id = 1, that is also stored in the database.
<?php
namespace App\Http\Controllers;
use App\Category;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
public function index()
{
$categories = Category::paginate(3);
return view('admin.categories.index',compact('categories'));
}
public function edit(Category $category)
{
return "This is category edit page";
// dd($category);
// $categories = Category::where('id','!=', $category->id)->get();
// // dd($categories);
// return "This is category edit page";
// return view('admin.categories.create',['categories' => $categories, 'category'=>$category]);
}
When I try to go to this edit category page, it shows 404 page not found error.
Although, when I made an individual route for edit method with a closure function to return some text, it worked perfectly.
Route::get('category/{category}/edit', function($category){
return $category;
})->name('category.edit');
You didn't excluded full error you get, but try to change:
public function edit(Category $category)
{
return "This is category edit page";
}
into:
public function edit($category)
{
return "This is category edit page";
}
and see if it helps. If it helps, it means that there is no record matching id you passed or this record is soft deleted (or some additional conditions are not met) - Laravel uses Route model binding to match valid record.
try this
public function edit(Request $category)
{
return "This is category edit page";
}

How to condition route model bindings by actions in RouteServiceProvider

I have an application which needs to accomplish this in RouteServiceProvider.php:
//in \App\Providers\RouteServiceProvider.php
public function boot(Router $router)
{
//
parent::boot($router);
//somehow can get the current action
$action = $router->getCurrentAction();
if($action == 'edit'){
$router->model('articles','App\Article');
} else{
$router->bind('articles', function($id){
return Article::published()->findOrFail($id);
});
}
}
Here is my route:
Route::resource('articles', 'ArticlesController');
Here is my Controller:
public function show(Article $article){
return view('articles.show',compact('article'));
}
public function edit(Article $article){
return view('articles.edit',compact(['article','tags']));
}
The reason I want to do it because I want show action only shows published articles while edit action can change both published and unpublished articles.
if there is any better solution, please teach me. Thank you !
Why don't you make a middleware, that will work only for 'published' routes, where you will check if your Article is published?
Based in your route, I assume that you have the following paths:
example.com/edit
example.com/3 - article ID
So, you could use a pattern to bind the article:
public function boot(Router $router)
{
parent::boot($router);
// bind
$router->bind('article', function($id){
return Article::published()->findOrFail($id);
});
// id pattern
$router->pattern('id', '[0-9]+');
}
Now, just declare the respective routes:
Route::get('articles', 'ArticlesController#showAll');
Route::get('{id}', 'ArticlesController#edit');
Finally, your controller could looks like this:
class ArticlesController{
public funcion showAll(){
// show a list of articles
}
public function edit(Article $article){
// selected article
}
}
Try to get the best of Laravel using class injection and keeping cleaning code.

Resources