Multiple update methods in same controller Laravel 6 - laravel

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,
...........
]);
}

Related

How to create Laravel api route endpoint/query parameters?

I would like to be able to filter the json response using some fields in the database e.g. api/v1/user?username=mary but don't know how to do this. My second question is that the route api/v1/user/3 is working but I can't remember how I set this up as I did it some time ago. Can anyone help?
api.php
Route::group(['prefix' => 'v1'], function () {
Route::apiResource('/user', 'UserController');
});
user resource
public function toArray($request)
{
return parent::toArray($request);
}
user controller
public function show(User $user): UserResource
{
return new UserResource ($user);
}
public function index(): UserResourceCollection
{
return new UserResourceCollection(User::orderBy('created_at', 'desc')
->paginate(5)
);
}
public function store(Request $Request)
{
$request->validate([
'first_name' => 'required',
'last_name' => 'required',
'email' => 'required',
]);
$user = User::create($request->all());
\Mail::to($user)->send(new Welcome);
return new UserResourse($user);
}
public function update(User $user, Request $request): UserResource
{
$user->update($request->all());
return new UserResource($User);
}
public function destroy(User $user)
{
$user->delete();
return response()->json();
}
}
UPDATED
I have seen several tutorials with the advice that the user has given below but I don't know how to put it together because I already have a show method above. I tried commenting out the show method and creating another show method for the query string
public function show(User $user): UserResourceCollection
{
$request->input('username');
return new UserResourceCollection(User::orderBy('created_at', 'desc')
->where('username', '=', $username)
->paginate(2)
);
}
and added a GET route
Route::group(['prefix' => 'v1'], function () {
Route::apiResource('/user', 'UserController');
Route::get('/user/{username?}','UserController#show');
});
This is working as an endpoint. The pagination part is working I made it smaller so I know it's calling the method but it is searching by id and i want to search by username. Ideally I want to use a query parameter like api/v1/user?username=mary.
To get json request, you can call $request->input('name') for example.
You can setup the resource action on controller. By example, you can create UserController.show method. So, the GET /user/{id} method will be handled by UserController.show
For more example, you read the documentation.
I don't think it's possible to create api url parameters. I started again using this tutorial
https://www.youtube.com/watch?v=z3YPhYwcbBM.
This way means I always have to know the id (search by product id rather than filtering reviews by query search) which isn't ideal
e.g. http://localhost:8000/api/v1/products/2/reviews
however I can add more endpoints in place of reviews like categories etc.

Laravel: How to use the same post form for multiple sections

I want to build something like facebook and I have a form where the user can post content but I want to use the same form on different sections, for example: groups, pages, profile.
I have PostController that is a resource that receives the post requests but I need a way to differentiate between sections in order to store the data with the correct section_type and section_id.
// Post Model Post.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['content', 'user_id'];
public function section()
{
return $this->morphTo();
}
public function user()
{
return $this->belongsTo(User::class);
}
public function group()
{
return $this->belongsTo(Group::class);
}
public function page()
{
return $this->belongsTo(Page::class);
}
}
The User.php Model
class User extends Authenticatable
{
public function posts()
{
return $this->morphMany(Post::class, 'section');
}
}
and this is the PostController and store() function where I have only one situation at this moment where a post is stored in section_type App\User, but I need a way to store it in App\Group or App\Page also.
public function store(Request $request)
{
$this->validate(request(),
[
'content' => 'required|min:5',
]);
$user = User::find(Auth::id());
$user->posts()->create([
'content' => $request->content,
'user_id' => Auth::id()
]);
return redirect('/');
}
What do I need to do in PostController.php?
I thought maybe I could use a post request with parameters in the form, like this for posting in groups
<form method="post" action="/?group=1">
or this for posts in pages
<form method="post" action="/?page=1">
And after that use $request->query() to get the section and id. Do you have other ideas?

getting user profile using a slug

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);
});
}

Laravel 5.2 - middleware auth

i just installed laravel 5.2, and i created auth register, login, and reset password, but now i want create a index of my project where all user (also not logged) can access. i tryed to create
Route::get('/',HomeController#home');
But this view is enable only for users logged.
MY ROUTES
Route::auth();
Route::get('/home', 'HomeController#index');
// POST - FORM CREA
Route::get('/crea-regalo', 'PostController#form');
Route::post('/crea-regalo', 'PostController#creaPost');
// LISTA ANNUNCI PRINCIPALE
Route::get('/', 'HomeController#home');
MY HOME CONTROLLER
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$posts = Post::orderBy('id','DESC');
return view('home', compact('posts'));
}
public function home()
{
$posts = Post::all();
return view('index', compact('posts'));
}
}
How can i create routes of view where ALL users can access?
Thank you for your help!
Hi write separate controller to access page to all because you have written auth middleware in contructor
public function __construct()
{
$this->middleware('auth');
}
Similar like
class GuestController extends Controller
{
public function __construct()
{
}
public function home()
{
$posts = Post::all();
return view('index', compact('posts'));
}
}
In route
Route::get('/home', 'GuestController#home');
or else you can do like this
$this->middleware('auth', ['except' => ['home']]);
this will able to access home page for all .In your constructor add this
public function __construct()
{
$this->middleware('auth', ['except' => ['home']]);
}
Put those route which you want to allow only authenticated user in middleware auth as follows:
Route::group(['middleware' => ['auth']], function () {
//your routes
})
And for those routes which all user can access put that out side the above group.

How to redirect store to update method?

How to redirect store to update method? I tryed the following code:
public function store(ProductRequest $request)
{
return $this->update(new Product, $request);
}
public function update(Product $product, ProductRequest $request)
{
// code
}
However, the first parameter of update need an already in database user and the above code does not work as expected. (it update the entire users in db!)
What is the correct way to achieve that?
public function store(UserRequest $request)
{
return $this->maintain(new User, $request);
}
public function update(User $user, UserRequest $request)
{
return $this->maintain($user, $request);
}
private function maintain($user, $request)
{
//code;
}
The model for the update method could be the problem, your code is okay for this part:
public function store(Request $request)
{
return $this->update(new Product, $request);
}
public function update(Product $product, Request $request)
{
$product->fill($request->all())->save();
// code
}
For example, with route model binding:
Route::resource('products', 'ProductController');
Route::model('products', App\Product::class);
Or with a custom binding:
Route::resource('products', 'ProductController');
Route::bind('products', function($param) {
return Product::where('slug', $param)->first();
});
Make sure you are not using get() in custom binding, it will pass back a collection.

Resources