When I'm updating my model-bound form with
$user->update(Input::all())
My password field is re-hashed, even when it's empty. I have set my User.php class to automatically hash that field, but shouldn't it be skipped since the field is empty?
You could use in this case:
Input::except('password')
so in your controller you could do it this way:
if (trim(Input::get('password')) == '') {
$data = Input::except('password');
}
else {
$data = Input::all();
}
$user->update($data);
However you should consider other possible issues for that. In this case if user send input with id name (and anyone can do it even if you don't have such field in your form) he could change easily other users passwords/accounts and destroy your whole data.
You should use in your User model at least:
protected $guarded = array('id');
to protect user id from being changed during mass assignment but maybe there are also some other fields you would like to protect (you should list them in $guarded array.
For me much better option in this case is using standard user updating:
$user = User::find($id);
if (trim(Input::get('password')) != '') {
$user->password = Hash::make(trim(Input::get('password')));
}
$user->name = Input::get('name');
// and so on - this way you know what you are changing and you won't change something you don't want to change
$user->save();
Just as Tom Bird commented, here's some code for an example.
If you use a mutator like setPasswordAttribute() method in your model then you can do this:
public function setPasswordAttribute($password)
{
if (!empty($password))
{
$this->attributes['password'] = bcrypt($password);
}
}
This will prevent a new password from being hashed. This setPasswordAttribute() method is called a "mutator" and became available in Laravel 4.2 from what I see. http://laravel.com/docs/4.2/eloquent
Because you have sent all of the input to the user model it assumes you want to update all fields including the password even though it is an empty string, it is possible to hash an empty string.
You need to check if the password is empty and if it is use Input::except('password')
The simple method you can use for this is array_filter. Array_filter filter excludes any empty field. so if you password field is empty then it will not be included in the user update model and when the password field is not included it will not be hashed since mutators and accessors only work when the model has the given attribute. When you filter it out the fields, the model does not receive the field and thus will not hash. You use it in following way...
$user->update(array_filter(Input::all()));
or
$user->update(array_filter($request->all()));
The only problem with this is it will not only exclude password but also all the field that were set empty.
public function update($id)
{
$register = Register::findOrFail($id);
if (empty(Request::get('password'))) {
$data = Request::except('password');
} else {
$data = Request::all();
}
$register->update($data);
return redirect('register');
}
Related
I have a form that is sending the values to the controller in this way:
public function postFormUpdate(ProjectUpdateRequest $request)
{
$inputs = $request->all();
$project = $this->projectRepository->update($inputs['project_id'],$inputs);
//...
}
The project repository is done this way:
public function update($id, Array $inputs)
{
return $this->save($this->getById($id), $inputs);
}
private function save(Project $project, Array $inputs)
{
// Nullable
if (isset($inputs['project_type'])) {$project->project_type = $inputs['project_type'];}
if (isset($inputs['activity_type'])) {$project->activity_type = $inputs['activity_type'];}
...
}
My problem is if the project_type is null from the form field (the project type doesn't need to be entered or can be removed), then isset($inputs['project_type']) will be false and the update will not be triggered.
What I want is if the user had set up a project type and then wants to change it and set it to null, like this, it is not working. I use the isset because sometimes I update only one field and I don't want this to generate an error because it was not part of the inputs and was not set.
What I can do is use:
if (isset($inputs['project_type']) || is_null($inputs['project_type'])) {$project->project_type = $inputs['project_type'];}
But I am looking if there is a more elegant way to do this.
Thanks.
A more elegant way would be to see if anything is set under the key.
so go with array_key_exists
if ( array_key_exists('project_type', $inputs) ){$project->project_type = $inputs['project_type'];}
You may see it in action here
When a new user is registered and is redirected to profile page. All these $userconatact , $qualification and $profileimage variables are null. Home page is setup with if (condition) to have buttons to fill form or show available data to user. There are three forms and user has to fill these form one by one. All these variables or one of them could be null but I still want to send the null value to view. Is there any way to make this view happen.
class ProfileController extends Controller
{
public function showprofile($type=null, $id='id'){
$contactquery = Usercontact::where('user_id',Auth::user()->id)->select('*')->get();
$usercontact = $contactquery->toArray();
$qualificationquery = userqualification::where('user_id',Auth::user()->id)->select('*')->get();
$qualification = $qualificationquery->toArray();
$profileimagequery = Profileimage::where('user_id',Auth::user()->id)->select('id','user_id','profileimage')->get();
$profileimage = $profileimagequery->toArray();
return view('home')->withUsercontact($usercontact)->withQualification($qualification)->withProfileimage($profileimage);
}
}
I tried using if statements but if didn't work
return view('home')
if(!empty($usercontact)){->withUsercontact($usercontact)}
if(!empty($qualification)){->withQualification($qualification)}
if(!empty($profileimage)){->withProfileimage($profileimage);}
Is there any way to use if statements like this to make it easy.
1) Use compact which will automatically create key value pairs for you.
return view('home')->compact('usercontact','qualification','profileImage')
2) Here are a few other improvements to your code. You can use the Auth facade to access the logged-in user.
$usercontact = Auth::user();
3) Define relationships on your user model and access the qualifications by this. This will return a Collection.
$qualification = $usercontact->qualifications;
You can use compact to send data from your controllers to views.
return view('home')->compact('usercontact', 'qualification', profileimage');
Your code can be refactored as below.
public function showprofile($type=null, $id='id')
{
$usercontact = Usercontact::where('user_id',Auth::user()->id)->first();
$qualification = Userqualification::where('user_id',Auth::user()->id)->first();
$profileimage = Profileimage::where('user_id',Auth::user()->id)->select('id','user_id','profileimage')->first();
return view('home')->compact('usercontact', 'qualification', 'profileimage');
}
Note the Userqualification model name in the code according to the convention. Try to add relationships to your models to make your query easier.
Try this style to send data to view
return view('home',['Usercontact'=>$usercontact,'Qualification'=>$qualification,'Profileimage'=>$profileimage]);
In view you will be able to get data by array key
Is there any way to update a record in Laravel using eloquent models just if a change has been made to that record? I don't want any user requesting the database for no good reason over and over, just hitting the button to save changes. I have a javascript function that enables and disables the save button according with whether something has changed in the page, but I would like to know if it's possible to make sure to do this kind of feature on the server side too. I know I can accomplish it by myself (meaning: without appealing to an internal functionality of the framework) just by checking if the record has change, but before doing it that way, I would like to know if Laravel eloquent model already takes care of that, so I don't need to re-invent the wheel.
This is the way I use to update a record:
$product = Product::find($data["id"]);
$product->title = $data["title"];
$product->description = $data["description"];
$product->price = $data["price"];
//etc (string values were previously sanitized for xss attacks)
$product->save();
You're already doing it!
save() will check if something in the model has changed. If it hasn't it won't run a db query.
Here's the relevant part of code in Illuminate\Database\Eloquent\Model#performUpdate:
protected function performUpdate(Builder $query, array $options = [])
{
$dirty = $this->getDirty();
if (count($dirty) > 0)
{
// runs update query
}
return true;
}
The getDirty() method simply compares the current attributes with a copy saved in original when the model is created. This is done in the syncOriginal() method:
public function __construct(array $attributes = array())
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
public function syncOriginal()
{
$this->original = $this->attributes;
return $this;
}
If you want to check if the model is dirty just call isDirty():
if($product->isDirty()){
// changes have been made
}
Or if you want to check a certain attribute:
if($product->isDirty('price')){
// price has changed
}
You can use $product->getChanges() on Eloquent model even after persisting. Check docs here
I like to add this method, if you are using an edit form, you can use this code to save the changes in your update(Request $request, $id) function:
$post = Post::find($id);
$post->fill($request->input())->save();
keep in mind that you have to name your inputs with the same column name. The fill() function will do all the work for you :)
use only this:
Product::where('id', $id)->update($request->except(['_token', '_method']));
At times you need to compare the newly changed value with the previous one and if you are looking for that here is the solution.
if (
$obj->isDirty('some_field_name') &&
$obj->some_field_name != $obj->getOriginal('some_field_name')
) {
// Make required changes...
}
});
}
The reference of the derived solution is here.
Maybe Laravel has updated since, but wasChanged is working for me better than isDirty in all of these previous answers.
For example:
if($post->wasChanged('status') && $post->status == 'Ready') // Do thing
I am using the ORM to save the user registration data into the database. The code is as follows.
if ($_POST) {
$user = Model::factory('member');
$post = $user->validate_create($_POST);
if ($post->check()) {
$user->values($post);
$user->save();
// redirect to create gallery.
}
}
I have some values such as the UserType which is not part of the $_POST but has to be saved in the members table as part of the user registration. Is it a good idea to alter the values of $post and add UserType to it or is there any other recommended methods for achieving this?
It's ok to alter the $post since it's just an array with the values taken from request now.
You can do it either by editing the $post array:
$post['usertype'] = 'customer';
$user->values($post);
$user->save();
Or you can set the value to your ORM object directly:
$user->values($post);
$user->usertype = 'customer';
$user->save();
Both should be fine
You can use hidden inputs in your form. For example:
Form::hidden('usertype', 'customer');
If you don't want to change $_POST array.
If you want to check is user sending $_POST request, use Kohana's method:
if($this->request->method() === Request::POST) {}
instead of:
if($_POST)
By the way, get a $_POST data in this way:
$post = $this->request->post();
Kohana's ORM comes with built in Kohana's Validation.
As much as I understood, it validates fields that will be added to
the database. It won't work for me because I need to validate fields
that come from $_POST (in simple speaking).
Let me give you an example.
In controller:
$data = Arr::extract($this->request->post(), array('username', 'password', 'password_repeatedly', 'email'));
try {
ORM::factory('User')->sign_up($data);
$this->request->redirect('sign-in');
} catch(ORM_Validation_Exception $exception) {
$errors = $exception->errors('error_messages');
echo 'There were errors:<br />';
echo Debug::dump($errors);
exit;
}
Variable $data is array I need to validate. Method sign_up() is
just custom method in my ORM model that will create user. Sorry about
"echo'es" and "exit's" in controller - I'm just debugging...
My ORM model looks like this:
public function rules() {
return array(
'username' => array(
array('not_empty')
),
'hashed_password' => array(
array('not_empty')
),
'email' => array(
array('not_empty')
)
);
}
public function sign_up($post) {
$salt = $this->_hurricane->generate_salt();
$hashed_password =
$this->_hurricane->hash_password($post['password'], $salt);
$this->username = $post['username'];
$this->hashed_password = $hashed_password;
$this->salt = $salt;
$this->email = $post['email'];
$this->save();
}
I want to check that those three elements of variable $data are
NOT empty! As I said, it checks elements before ORM::save() is
called. And if ypu look closer at my code... in my custom method I
have set hashed_password to be something. It will make it hashed.
Problem is that if user haven't submitted any password (I call that
field 'password' in my HTML form, but 'hashed_password' in
database)... if no password is submitted - it will hash empty string
that will lead to hash anyway. So hashed_password is set!
Then validation is turned on by ORM::save() and in conclusion -
password never can be possibly empty! How to deal with this? Extra
validation in controller? How would you deal with it? Maybe a little
bit different logic?
P.S. Any other suggestions to my code will be appreciated. Thanks in advice!
I don't see what is 'wrong' with your current method.
You can add a condition (Model_user::signup()) to check if the requested password is empty before hashing it (ofc, not setting it at all if it is), so it'll remain empty and make validation fail.
One more thing I can notice here is that the signup method itself is ambiguous, it could easily be done using normal create() combined with a filter for password (so that hashed_password and salt are set when it's changed).
Imho it's also a good practice to use conditional rules / filters, depending on the current objects' state.