So in addition to my prior topic (thank you guys for helping) routes with compact
I am now facing troubles with my store function, I am getting the error : "Trying to get property of non-object.
This is my store function in my Controller
public function store(Request $request)
{
// validate the data
$this->validate($request, array(
'title' => 'required|max:255',
'body' => 'required'
));
// store in the database
$userpost = new Usp;
$userpost->title = $request->title;
$userpost->body = $request->body;
$userpost->save();
Session::flash('success', 'The blog post was successfully saved!');
return redirect()->route('admin.userposts.show', $userpost->id);
}
This is the view to create userpost(to make it more clear, p.s. the same form with different route ofcourse, works for my simple posts but not for my user submitted posts)
#extends('index')
#section('index-stylesheets')
{!! Html::style('css/parsley.css') !!}
#endsection
#section('content')
<h1>Create New User Post</h1>
<hr>
{!! Form::open(array('route' => 'admin.userposts.store', 'data-parsley-validate' => '')) !!}
{{ Form::label('title', 'Title:') }}
{{ Form::text('title', null, array('class' => 'form-control', 'required' => '', 'maxlength' => '255')) }}
{{ Form::label('body', "Post Body:") }}
{{ Form::textarea('body', null, array('class' => 'form-control', 'required' => '')) }}
{{ Form::submit('Create Post', array('class' => 'btn btn-success btn-lg btn-block', 'style' => 'margin-top: 20px;')) }}
{!! Form::close() !!}
#endsection
#section('index-scripts')
{!! Html::script('js/parsley.min.js') !!}
#endsection
Method of showing the post:
public function show($id)
{
$userpost = Usp::find($id);
return view('admin.userposts.show', compact('userpost'));
}
So the fact is that the problem was not the store method but the routes.
Route::get('/userposts/{id}', 'UserPostsController#show')->name('admin.userposts.show');
Route::get('/userposts/create', 'UserPostsController#create')->name('admin.userposts.create');
Route::post('/userposts/store', 'UserPostsController#store')->name('admin.userposts.store');
When registering the routes in that order, when laravel will iterate over your routes, it will first encounter the show one, and it will therefore take "create" as the id. Therefore, it will go into the show method and it won't find any post that matches, the post being null, you get the error.
So, there are two ways of fixing this.
The first one (the easiest, works in all cases, maybe not the best) is to put the create route before the show route.
The second one, the best in my opinion, is to add a condition to the id (doesn't work in the case of a slug). As the ids are only integers, you get :
Route::get('/userposts/{id}', 'UserPostsController#show')->name('admin.userposts.show')->where('id', '[0-9]+');
Therefore, create won't match the regular expression and it won't go in the show method.
For "resource creations" (storing in database), I wouldn't use a "field-by-field" method.
Instead, I'd do something like this :
$userpost = Usp::create($request->only('title', 'body'));
I feel this is more talkative.
But, it won't work, laravel protects* us against such things. To make it work, you have two options.
(The best option in my opinion)
In your model, add a protected variable called $fillable with all your columns that you allow to mass assign*. In this case you would put :
protected $fillable = ['name'];
(The option if you are sure of what are you doing)
In your model, you can say, hey, I know what I'm doing here, just let me do my stuff without guarding me. In this case you would put :
protected $guarded = [];
Notes :
$request->only('field1', ...) gives you an array of the fields that you want with the fields name as keys, in this case it gives you ['field1' => $request->field1]. In your case it will give you ['title' => $request->title, 'body' => $request->body].
Mass assignment is when you give an array to the model and it puts all attributes to the fields of the array. More informations here https://laravel.com/docs/5.4/eloquent#mass-assignment
When I mean laravel protects us against those things, it does't really protect us because it isn't a bad practice (instead, I find it more readable), but because it does allow you to make mistakes (for exemple, setting fields that don't exist).
Related
any expert here ? This is a very strange problem I am facing.
I have my website hosted on an aws machine. The code was working absolutely fine there. Then it was shifted to another server and this strange problem staeted to appear.
I have a route to update a car
Route::put('vehicles/{vehicle}', 'VehicleController#update');
Edit form
{!! Form::model($vehicle, ['url' => ['backend/vehicles', $vehicle->id], 'method' => 'put','files' => true , 'class' => 'form-horizontal form-label-left', 'role' => 'form']) !!}
#include( 'backend.vehicles.form' )
{!! Form::close() !!}
Now here is where the strange behaviour start, whenever I try to update a car which was created prior to the server move, It shows me MethodNotAllowedHttpException in RouteCollection.php
But when I create a car and then updates this new car, Operation succeeds. Please help.
One more thing, In routeCollection.php where it matches a route for a request, It shows GET method for old car but put method for new car
public function match(Request $request){
// die($request->getMethod()); $routes = $this->get($request->getMethod());
$route = $this->check($routes, $request);
if (! is_null($route)) {
return $route->bind($request);
}
// If no route was found we will now check if a matching route is specified by
// another HTTP verb. If it is we will need to throw a MethodNotAllowed and
// inform the user agent of which HTTP verb it should use for this route.
$others = $this->checkForAlternateVerbs($request);
if (count($others) > 0) {
return $this->getRouteForMethods($request, $others);
}
throw new NotFoundHttpException;
}
Please anyone.
Add this inside the form
{{ method_field('PUT') }}
or in HTML
<input type="hidden" name="_method" value="PUT">
Please try the following solution:
Route::put('vehicles/{vehicle}', 'VehicleController#update');
Change to
Route::match(['put', 'patch'], 'vehicles/{vehicle}', 'VehicleController#update');
And the form to
{!! Form::model($vehicle, ['action' => ['VehicleController#update', $vehicle->id], 'method' => 'put','files' => true , 'class' => 'form-horizontal form-label-left', 'role' => 'form']) !!}
#include( 'backend.vehicles.form' )
{!! Form::close() !!}
Does it work for you?
So I have this CRUD where I use the same form to create and edit entries.
I need in several form selects, when creating (no data present for that particular field yet) my select to show the placeholder, but when editing, my select to show whatever is stored on database for that particular id filed. So I have:
Controller:
...
public function create()
{
$house = houses::pluck('name', 'id');
//$thisclient = null;
$clients = client::pluck('last_name', 'id');
$reps = user::where('role_id', 5)->orderBy('first_name')->get()->pluck('full_name', 'id');
return view('prospects.create', compact('house', 'clients', 'reps'));
}
...
public function edit($id)
{
$house = houses::pluck('name', 'id');
//$thisclient = user::whereId($id)->first();
$clients = client::pluck('last_name', 'id');
$reps = user::where('role_id', 5)->orderBy('first_name')->get()->pluck('full_name', 'id');
$prospect = Prospect::findOrFail($id);
return view('prospects.edit', compact('prospect', 'house', 'clients', 'reps'));
}
and my view form:
Working for create:
{!!Form::select('client_id', $clients, null, ['class' => 'form-control', 'placeholder' => 'Please Select'] ) !!}
Working for edit:
{!! Form::select('client_id', $clients, $prospect->client_id, ['class' => 'form-control'] ) !!}
I'm having 2 troubles here, if I have null as my selected field, it won't bring the selected data on edit, if I have $prospect->client_id , it will return a error on create as there's no data yet.
I tried to solve this by creating a variable $thishouse on controller and passing it to view on return view('prospects.create', compact('house', 'thisclient','clients', 'reps')); and view Form::select('client_id', $clients, $thisclient, ['class' => 'form-control'] ) !!} but seems a bit dirty whne having several form selects...
The second trouble is if I leave a placeholder on Edit, it will show the placeholder, not $prospect->client_id itself.
What's the best and simplest way to achieve all of this and use the same form for create and edit?
Thanks
You can use Form::open and Form::model to create and edit. As an example, you can set in your view:
#if(isset($prospect))
{!! Form::model($prospect, ['action' => ['ProspectController#update', $prospect->id], 'method' => 'patch']) !!}
#else
{!! Form::open(array('action' => 'ProspectController#store', 'method' => 'POST')) !!}
#endif
And then you can create the select like this:
{!! Form::select('client_id', $clients, old('client_id'), ['class' => 'form-control'] ) !!}
So, when you are editing, Laravel will select the attribute from the variable on model function.
And since you are using Laravel 5.5, you could also use #isset instruction.
I'm implementing bootstrap-slider in my CRUD, I have implemented it successfully in Create, the problem is when I try to edit it,
I want to get the current value from the Model. Idk how to do this.
This is for PATCH.
<div class="form-group">
<h3 class='box-title text-info'>Percentage</h3>
{!! Form::input('text','percentage',null,['id'=>'ex8', 'data-slider-id'=>'ex1Slider', 'data-slider-min'=>'0', 'data-slider-max'=>'100', 'data-slider-step'=>'5', 'data-slider-value'=>'50']) !!}
</div>
In your form instead of creating a new form. You will bind the form to the model.
{!! Form::model('modelname', [options here] !!}
All the fields will math the model's property values.
Edit
Here is an example
You must used something like this to create a EDIT FORM
{{ Form::model($smartphones, ['method' => 'PATCH', 'url' => 'smartphones/'.$smartphones->id]) }}
You get by using $(your_model)['inputID']...You can use in "data-slider-value"... Something like this
{{ Form::input('text','mem_ram', null, ['id' => 'mem_ram', 'data-slider-value'=>$smartphones['mem_ram']]) }}
I was doing great so far until I ran into another problem with validation. I'm trying to update a user related table called socialLinks. The problem is every time I update, since it's a model backed form, the prefilled values in the form gets pass through validations and I get a 'has already been taken' error in return.
After doing a bunch of googling, I tried to pass userId through update, but i haven't had any success. I had this problem before but I was validating a column from User. Now I'm trying to validate a column from another table with a relationship with user and nothing I tried before works. Super Frustrating.
my form
{!! Form::model($user_links,['method' => 'PATCH', 'action'=> ['UserController#update_social']]) !!}
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('facebook', 'Facebook Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('facebook', null,['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('twitter', 'Twitter Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('twitter', null,['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('reddit', 'Reddit Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('reddit', null,['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-3'>
{!! Form::submit('Save Changes',['class'=>'btn btn-md btn-success']) !!}
{!! Form::close() !!}
routes
Route::get('/account/social','UserController#social');
Route::patch('/account/social','UserController#update_social');
and controllers
public function social(Request $request){
$user = $request->user();
$user_links= $request->user()->links;
return view('user.edit.social_connect',compact('user_links','user'));
}
public function update_social(Request $request){
$user = $request->user();
$validator=Validator::make($request->all(),[
'facebook' => 'unique:social_links,facebook,'.$user->id,
'twitter' => 'unique:social_links,twitter'.$user->id,
'reddit' => 'unique:social_links,reddit,'.$user->id,
'google' => 'unique:social_links,google,'.$user->id
]);
if ($validator->fails()){
var_dump($user->id);exit;
return Redirect::back()->withErrors($validator)->withInput();
}
$data=Input::all();
$links = $user->links;
if ($links == null){
$links = new SocialLinks();
$links->fill($data);
$links->user_id=$user->id;
$links->save();
}else{
$links->fill($data);
$links->save();
}
return Redirect::back()->with('message','Your profile has been updated');
}
Update put validation logic in controller
this is what worked for me
$user = $request->user();
$id = $user->id;
$validator=Validator::make($request->all(),[
'facebook' => 'unique:social_links,facebook,'.$id.',user_id',
'twitter' => 'unique:social_links,twitter,'.$id.',user_id',
'reddit' => 'unique:social_links,reddit,'.$id.',user_id',
'google' => 'unique:social_links,google,'.$id.',user_id',
]);
I honestly don't get why though. Why do we concatenate id to exclude it from being validated? the syntax makes no sense to me. Also $id comes from user object, and 'user_id' is from my social links table. Am I matching ids here? Somebody please show me the light ;(
To start: In general, extending the Laravel Request class and dependency injecting your extended class into your controller functions, although it can be done, is a bad idea. Read this to understand why (although it may not appear to be related at first read):
Laravel 5 / Codeception not routing correctly
Basically the problem is that if your validation class throws a perfectly legitimate validation exception, that exception has to be trapped by the Laravel router and not by the controller function. Essentially unless the validation passes your controller function never gets called, and so it can't trap the validation exception. This frequently results in either a 500 error or a redirect to a completely different page (which is why this screws up codeception tests amongst other unwanted side-effects).
So a better plan is to pass a Laravel Request object into your controller function and validate inside the function, rather than attempting to get Laravel to do it for you.
Once you resolve that issue, getting the validation code to handle the case where the $user does not exist should be easy. Some suggestions for your validation code to handle that validation (which should now be inside your controller function, or in a separate validator class called from your controller function):
Request probably doesn't contain a User object. It might contain a user_id variable which you can turn into a User object using User::find($user_id) or similar.
Check to ensure that $user is not null before attempting to work with $user->id or you'll get an error. If the $user_id passed in is empty or invalid then User::find($user_id) will return null. Check for this case and throw an exception first, before you continue to look at $userId or save any links.
I can't see exactly what you're doing in your form but if the above doesn't resolve your issues then post the form here and we can take another look.
You need to edit validation for updating, this is my example from one app :
public function rulesAdmin($id = NULL)
{
return [
'name' => 'required|min:5',
'username' => 'unique:users' . ($id ? ",username, $id" : ''),
];
}
on editing ->you pass from database $id, on saving new record -> $id is NULL.
I'm working on a website that searches a database of organizations. On the search page, there are two search fields: one for searching by record name, and one searching the organization's subjects.
Now, normally, I would have no problem setting up placeholders in my URIs.
Route::get('/search/{name}', function($name)
{
//code...
});
And I use the post route to attach the parameters
Route::post('/search', array( 'as' => 'results', function()
{
$string = Input::get('search');
return Redirect::to("/search/$string");
}));
And the Laravel form would have no problem...
<h4>Search by Name</h4>
{{ Form::open(array('url' => "search") )}}
<p>
<div class="input-group input-group-lg">
<span class="input-group-btn">
{{ Form::button('Search', array('class' => 'btn btn-default', 'type' => 'submit'))}}
</span>
{{ Form::text('search', '', array('class' => 'form-control', 'placeholder' => 'Search by name')) }}
</div>
</p>
{{ Form::close() }}
But how do I attach a query string to this part?
{{ Form::open(array('url' => "search") )}}
How I would like my code to behave is when a query string is present, it searches by subject, not name. Doing this:
{{ Form::open(array('url' => "search/?subject=true") )}}
Doesn't actually attach it to my url.
The one thing I could do is just have a hidden input that tells the code to search by subject and not name, but that would mean any users who go to the url again will get different results. I don't want that behavior.
Any help? Laravel documentation doesn't help and I can't seem to find anyone online with the same problem.
[edit]
I found the trick to putting it into the url is by attaching the query string on the Route::post() like so:
$string = Input::get('search');
$subject = Input::get('subject');
return Redirect::to("/search/$string?subject=$subject");
But then Laravel gives me a NotFoundHttpException even after I change the final route to
Route::get('/search/{name}?subject={subject}', function($name, $subject)
Try
Route::get('/search',function($name)
{
//code...
if(Input::has('subject'))
$subject = Input::get('subject');
...
});
Laravel Router system already adds all of your non-route parameters as queries, so if you have a router:
Route::get('/search/{name?}', ['as' => 'search', function($name)
{
//code...
}]);
And you do
return Redirect::route('search', ['name' => 'laracon', 'subject' => 'true']);
It will redirect to:
http://server/search/laracon?subject=true
And
return Redirect::route('search', ['subject' => 'true']);
To
http://server/search?subject=true
And, of course, inside your router you have access to both of them:
Route::get('/search/{name?}', ['as' => 'search', function($name)
{
var_dump(Input::get('name'));
var_dump(Input::get('search'));
}]);