Allow saving an existing entry in Laravel with FormRequest and unique - validation

Still noob and learning Laravel, I am currently in the middle of a simple validation with FormRequest. What I am facing today is the edit of an existing entry.
I have written in my FormRequest that I want the name to be unique. It works perfectly but of course when I edit an existing entry, I cannot save it anymore, it already exists... of course it does since I am editing it.
I found the solution reading the documentation, but unfortunately, it does not work. Here's my code:
Routes:
Route::resource('editeurs', 'PublishersController');
Controller:
class PublishersController extends Controller
{
/* Update an existing publisher */
public function update($slug, PublisherRequest $request)
{
$publisher = Publisher::where('slug', $slug)->firstOrFail();
$input = $request->all();
$publisher->name = $input['name'];
$publisher->slug = my_slug($input['name']);
$publisher->save();
return redirect()->action('PublishersController#show', $publisher->slug);
}
}
FormRequest:
class PublisherRequest extends Request
{
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required|unique:publishers,name,'.?????
];
}
}
If needed, the view:
#section('content')
<div class="row">
<h1 class="large-12 columns">Edition - {!! $publisher->name !!}</h1>
{!! Form::model($publisher, ['method' => 'PATCH', 'action' => ['PublishersController#update', $publisher->slug]]) !!}
<div class="large-12 columns">
{!! Form::label('name', 'Nom de l\'éditeur') !!}
{!! Form::text('name', null, ['placeholder' => 'Nom de l\'éditeur']) !!}
</div>
<div class="large-12 columns">
{!! Form::submit('Ajouter un éditeur', ['class' => 'button expand']) !!}
</div>
{!! Form::close() !!}
</div>
#stop
What is wrong with my code?

Here is how I would do it:
class PublishersController extends Controller
{
/* Update an existing publisher */
public function update($slug, PublisherRequest $request)
{
$publisher = Publisher::where('slug', $slug)->firstOrFail();
$this->validate($request, ['name' =>'required|unique:publishers,name,'.$publisher->id]);
$publisher->name = $request->input('name');
$publisher->slug = my_slug($publisher->name);
$publisher->save();
return redirect()->action('PublishersController#show', $publisher->slug);
}
}

OK, I found the solution. I needed to pass the slug of my current publisher.
public function rules()
{
$publisher = Publisher::where('slug', $this->editeurs)->first();
return [
'name' => 'required|unique:publishers,name,'.$publisher->id
];
}
This works.

Related

Laravel problems with redirect

So I am working on a laravel project and I want that if a user types in their order code, the order will show up with the details. For some reason, the order code doesn't get through the if statement, because I get the output 'Order not found.' all the time, even if I type in an order code that is present in my orders table.
TrackController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Order;
class TrackController extends Controller
{
public function index()
{
return view ('track.index');
}
public function show($id)
{
$order = Order::where('code', $id)->first();
return view('track.show',[
'order' => $order
]);
}
public function redirect(Request $request)
{
$orderCode = $request->input('order-track-id');
$order = Order::where('code', $orderCode)->first();
if(!$order){
return redirect('/track')->with('error', 'Order not found.');
}else{
return redirect('/track/' . $order->code);
}
}
}
web.php
Route::get('/track', 'TrackController#index');
Route::post('/track/redirect', 'TrackController#redirect');
Route::get('/track/{id}', 'TrackController#show');
track.index
#extends('layouts/app')
#section('content')
<div class="container">
<div class="row justify-content center">
{!! Form::open(['action' => 'TrackController#redirect', 'method' => 'post']) !!}
{!! csrf_field() !!}
<input type="number" name="input-order-track-id" id="order-track-id">
{{ Form::button('Track', ['type' => 'submit', 'class' => 'btn btn-primary'] ) }}
{!! Form::close() !!}
</div>
</div>
#endsection
What am I doing wrong and why isn't my function putting me through to the show function in the TrackController?
In your redirect controller function.
public function redirect(Request $request)
{
$orderCode = $request->input('input-order-track-id');
$orders = Order::where('code', $orderCode)->get();
if($orders->isEmpty()){
return redirect('/track')->with('error', 'Order not found.');
}else{
$order = Order::where('code', $orderCode)->first();
return redirect('/track/' . $order->code);
}
}

Laravel Dynamic Checkbox error: Trying to get property 'id' of non-object

What I'm trying to achieve:
User can assign multiple supermarkets to a product, and supermarkets can be assigned to multiple products. When registering a product, I want the user to be able to select from check boxes which are populated from a database.
Product.php
class Product extends Model
{
//
protected $fillable = [
'name',
'summary',
'category_id',
'author_id',
'supermarket_id',
'gf_rank_id',
'average_price',
'photo_id',
'online_store_path',
'ingredients',
];
public function supermarket() {
return $this->belongsToMany('App\Supermarket');
}
}
Supermarket.php
class Supermarket extends Model
{
protected $fillable = [
'name',
'url',
];
public function products() {
return $this->belongsToMany('App\Products');
}
}
ProductsController.php
public function create()
{
$categories = Category::pluck('name', 'id')->all();
$supermarkets = Supermarket::pluck('name', 'id')->all();
return view('admin.products.create', compact(['categories', 'supermarkets']));
}
create.blade.php
#foreach ($supermarkets as $supermarket)
<div class="col-sm-3">
{!! Form::checkbox('supermarket_id[]', $supermarket->id) !!}
{!! Form::label('supermarkets', $supermarket) !!}
</div>
#endforeach
To explain what has been said in the comments:
You are not supplying an object in your $supermarkets data because you are using pluck('name','id'). You are supplying an associative array:
[
1 => 'supermarket A',
2 => 'supermarket B'
]
So you need to change your display code to:
#foreach ($supermarkets as $id => $name)
<div class="col-sm-3">
{!! Form::checkbox('supermarket_id[]', $id) !!}
{!! Form::label('supermarkets', $name) !!}
</div>
#endforeach

Issues with search query

I am trying to run a search query on all of my comments. I am encountering a number of problems. I would to have two search queries one that runs a search on the comment ID and another that runs a search on the username that is connected to the comment through the user_id FK.
Currently im getting the problem:
Too few arguments to function Illuminate\Support\Collection::get(), 0 passed in
Tables:
Comment- id, comment, user_id, timestamps
User - id, name, username
Models:
class Comment extends Model
{
public function author()
{
return $this->belongsTo('App\User','user_id');
}
}
Controller:
public function index(Request $request)
{
$comment =Comment::paginate(10);
$id=$request->input('id');
$name=$request->input('username');
if(!empty($id)){
$comment->where('id', $request->input('id') )->get();
}
if(!empty($name)){
$comment->where($comment->author->username, 'LIKE', '%'.$name.'%')->get();
}
return view('comments.index')->withComment($comment);
}
View:
<div class="panel-body">
{!! Form::open(['route' => 'comments.index', 'method' => 'GET']) !!}
<div class="col-md-5">
{!! Form::label('id', 'Search By ID:') !!}
{!! Form::text('id', null, array('class' => 'form-control')) !!}
</div>
<div class="col-md-5">
{!! Form::label('username', 'Search By Username:') !!}
{!! Form::text('username', null, array('class' => 'form-control')) !!}
</div>
<div class="col-md-2">
{!! Form::submit('Find Comments', array('class' => 'btn btn-send ')) !!}
</div>
{!!Form::close()!!}
</div>
#foreach($comment as $comments)
//data
#endforeach
The paginate function immediately executes the query for you, so you are using Collection functions after that. The get function on collections expects a key as a parameter, this is the problem.
To fix this, you can either remove the ->get() or use the paginate function at the end of your query as shown below.
$comment = Comment::query();
$id = $request->input('id');
$name = $request->input('username');
if (!empty($id)) {
$comment = $comment->where('id', $request->input('id'));
}
$result = $comment->paginate(10);
Since You have Paginated already
public function index(Request $request)
{
$comment = new Comment();
$id=$request->input('id');
$name=$request->input('username');
if(!empty($id)){
$comment->where('id', $request->input('id') )->get();
}
if(!empty($name)){
$comment->where($comment->author->username, 'LIKE', '%'.$name.'%');
}
return view('comments.index')->withComment($comment->paginate(10));
}
You cannot paginate and get it again, its like using SELECT statement twice on same object.

Laravel post error

I'm getting the following error message when trying to update user data:
protected function methodNotAllowed(array $others)
{
throw new MethodNotAllowedHttpException($others);
}
I'm logging the user in, then want to give them the option to change their preferences. The form displays fine in the view but won't post.
Here are my routes:
Route::prefix('admin')->group(function(){
Route::get('/login', 'Auth\AdminLoginController#showLoginForm')->name('admin.login');
Route::post('/login', 'Auth\AdminLoginController#login')->name('admin.login.submit');
Route::get('/', 'AdminsController#index')->name('admin.dashboard');
Route::post('/', 'AdminsController#update')->name('admin.dashboard.update');
Route::get('/logout', 'Auth\AdminLoginController#logout')->name('admin.logout');
Here's the Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Admin;
use Auth;
class AdminsController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth:admin');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$id = Auth::user()->id;
$admin = Admin::find($id);
return view('admin')->with('admin',$admin);
}
public function update(Request $request, $id)
{
$this-> validate($request, [
'target_sector' => 'required|max:255',
'target_skillsets' => 'required|max:255',
'target_companies'=> 'required|max:255',
'target_locations'=> 'required|max:255',
]);
//Create Post
$id = Auth::user()->id;
$admin = Admin::find($id);
$admin->target_sector = $request->input('target_sector');
$admin->target_skillsets = $request->input('target_skillsets');
$admin->target_companies = $request->input('target_companies');
$admin->target_locations = $request->input('target_locations');
$admin->save();
return redirect('/admin')->with('success', 'Preferences Updated', 'admin',$admin);
}
}
And here is the view:
#include('includes.nav_login')
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row mt-4">
<div class="col-md-10 offset-md-1">
<div class="card">
<div class="card-header">Admin Dashboard</div>
<div class="card-body">
#if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
#endif
You are logged in as ADMIN!
</div>
<div class="card-header">Update Vacancy Preferences</div>
<div class="card-body">
{!! Form::open(['action' => ['AdminsController#update', $admin], 'method' => 'POST']) !!}
<div class="form-group">
{{Form::label('companies', 'Companies')}}
{{Form::text('companies', $admin->target_companies,['class'=>'form-control', 'placeholder'=>'Target Companies'])}}
</div>
<div class="form-group">
{{Form::label('skillsets', 'Skillsets')}}
{{Form::text('skillsets', $admin->target_skillsets,['class'=>'form-control', 'placeholder'=>'Skillsets'])}}
</div>
<div class="form-group">
{{Form::label('sector', 'Sector')}}
{{Form::text('sector', $admin->target_sector,['class'=>'form-control', 'placeholder'=>'Sector'])}}
</div>
<div class="form-group">
{{Form::label('locations', 'Locations')}}
{{Form::text('locations', $admin->target_locations,['class'=>'form-control', 'placeholder'=>'Locations'])}}
</div>
{{Form::hidden('_method', 'PUT')}}
{{Form::submit('Update',['class'=>'btn btn-primary'])}}
{!! Form::close() !!}
</div>
</div>
</div>
</div>
</div>
#endsection
Can anyone explain why this isn't working?
You should fix you route, because you are using put method for update, but on routes, you defined as post
Route::post('/', 'AdminsController#update')->name('admin.dashboard.update');
Therefore error occurs.
You should fix your route like this,
Route::put('/{id}', 'AdminsController#update')->name('admin.dashboard.update');
I hope this help you.
The error says MethodNotAllowed which means you are hitting a route with a different request method than it accepts
you open the form like this
{!! Form::open(['action' => ['AdminsController#update', $admin], 'method' => 'POST']) !!}
so till now the form method is POST
but then you spoof the method to be of type put
{{Form::hidden('_method', 'PUT')}}
so now the method becomes of type put not post
however your route expects the method to be post
Route::post('/', 'AdminsController#update')->name('admin.dashboard.update');
This is why you get method not allowed exception
you either change the method on your controller to be put instead of post or remove the method spoofing thing from inside your form
I mean this line
//remove this
{{Form::hidden('_method', 'PUT')}}
once you fix it you will have another error because you don't have csrf field in your form so just add this inside of your form
#csrf
Really appreciate both answers on here - thanks #Mohammad Instanboli and #webdevtr.
Webdevtr was right to advise this:
Route::put('/{id}', 'AdminsController#update')->name('admin.dashboard.update');
I also had to go back and fix the following which I thought would be useful to note if anyone else views this with a similar issue:
Firstly my AdminsController#update method needed the following changes:
I changed the public function update to take one less variable - ($id)
public function update(Request $request)
{
$this-> validate($request, [
'target_sector' => 'required|max:255',
'target_skillsets' => 'required|max:255',
'target_companies'=> 'required|max:255',
'target_locations'=> 'required|max:255',
]);
//Create Post
$id = Auth::user()->id;
$admin = Admin::find($id);
$admin->target_sector = $request->input('target_sector');
$admin->target_skillsets = $request->input('target_skillsets');
$admin->target_companies = $request->input('target_companies');
$admin->target_locations = $request->input('target_locations');
$admin->save();
return redirect('/admin')->with('success', 'Preferences Updated', 'admin',$admin);
}
Then I needed to make sure the $request->input('x') matched the input names in the form in my view - i.e:
<div class="form-group">
{{Form::label('target_sector', 'target_sector')}}
{{Form::text('target_sector', $admin->target_sector,['class'=>'form-control', 'placeholder'=>'Sector'])}}
</div>

laravel Binding a property of the Model to selected values with getTagsAttribute()

i have problems with the model binding and the selected authors in the edit form and I used ->all() and it's still not working i have laravel 5.1.26
i tried and nothing happen and i tried
return $this->authors()->lists('id')->toArray();
my model Book.php
class Book extends Model
{
public function section()
{
return $this->belongsTo('App\Section','id');
}
/**
* many to many relation between author and books
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function author()
{
return $this->belongsToMany('App\Author','books_authors_relationship','book_id','author_id')->withTimestamps();
}
public function getAuthorListAttribute()
{
return $this->authors->lists('id')->all();
}
}
and my controller
public function edit($id)
{
$authors = Author::lists('first_name','id')->all();
$book = Book::find($id);
return view('books.edit_book',compact('book','authors'));
}
and my edit_book.blade
<div class="form-group ">
{!! Form::label('author_list', 'Enter Another Author:') !!}
{!! Form::select('author_list[]', $authors, null,['class'=>'form-control','multiple']) !!}
</div>
<div class="form-group ">
{!! Form::label('author_list', 'Enter Another Author:') !!}
{!! Form::select('author_list[]', $authors, $book->author->lists('id')->all(),['id' => 'authors','class'=>'form-control','multiple']) !!}
</div>
thanks every one

Resources