Laravel/Ardent/User model editing + saving

删除回忆录丶 提交于 2019-12-09 13:30:28

问题


what is the intended way to edit a user model with password in laravel/ardent? My problem is, that I do not want to load the actual user model from the db before the user input is validated correctly. Validation obviously fails when I leave the password field empty, because a password is required. This is my current post-edit-action:

public function postEdit($id)
{
    // ardent autohydrates this model
    $newUser = new User;

    // validation fails
    if(!$newUser->validate())
        return Redirect::action('UsersController@getEdit', $id)
            ->with('error', Lang::get('Bitte Eingabe überprüfen'))
            ->withErrors($newUser->errors())
            ->withInput(Input::except('password'));

    // load model from db
    $exUser = User::find($id);
    if(!$exUser->exists)
        return Response::make('No such user', 500);

    // save model, ardent autohydrates again?
    if($exUser->save())
        return Redirect::action('UsersController@getShow', $id)
            ->with('success', Lang::get('Änderungen gespeichert'));
    else
        return Redirect::action('UsersController@getEdit', $id)
            ->with('error', Lang::get('Bitte Eingabe überprüfen'))
            ->withErrors($newUser->errors())
            ->withInput(Input::except('password'));
}

this seems like an awful lot of code (+ it is not working), I was unable to find an example for this situation


回答1:


Ok, solved it myself, seeing as this is not a very active topic.

The problem was combining ardents autohydration feature and the unique requirement to retain the old password, if no new one is given. Because ardent autohydrates on validate() AND save(), there was no way to prevent autohydrating empty passwords too. First, I tried to change the Input array and overwrite it with the old password, but then I simply turned off the autohydration for the user model:

class User extends Ardent implements UserInterface, RemindableInterface {

    public $forceEntityHydrationFromInput = false;
    public $autoHydrateEntityFromInput = false;

This is the edit action on POST:

public function postEdit($id)
{
    // manually insert the input
    $user = new User(Input::all());

    // validate the user with special rules (password not required)
    if($user->validate(User::$updateRules)) {

        // get user from database and fill with input except password
        $user = User::find($id);
        $user->fill(Input::except('password'));

        // fill in password if it is not empty
        // will flag the pw as dirty, which will trigger rehashing on save()
        if(!empty(Input::get('password')))
            $user->password = Input::get('password');

        if($user->save())
            return Redirect::action('UsersController@getIndex')
                ->with('success', Lang::get('Änderungen gespeichert'));
    }

    return Redirect::action('UsersController@getEdit', $id)
        ->with('error', Lang::get('Bitte Eingaben überprüfen'))
        ->withErrors($user->errors())
        ->withInput(Input::except('password'));
}



回答2:


I ran into the same issue as you. After searching forever I read through the Ardent code and came up with this. It allows you to use one set of rules, auto hydration, auto hash passwords and the updateUnique() function of Ardent. I know it can be cleaned up and I'm sure theres a better way to do it but I've already spent way to much time on this issue.

This uses the dynamic beforeSave() closure in the controller(documented here). Since we are updating we check if there is a password being sent. If no password then set the password validation in the $rules array to blank, excluding password from validation. Since auto hashing passwords happens after validation and prior to beforeSave() we need to turn it off (set to false). The model is propagated a second time after passing validation so the submitted blank password field will be issued a Hash prior to beforeSave(), making it no longer blank and will fail our second check. When running updateUniques() 'or Save()' we pass a beforeSave closure checking again if there is a password being submitted, if not then remove it from the update.

tl;dr Prevent Ardent auto hydration from requiring and/or deleting passwords on administrative updates with minimal code.

Model:

class User extends Ardent implements UserInterface, RemindableInterface {

use UserTrait, RemindableTrait;

// Auto Hydrate
public $autoHydrateEntityFromInput   = true;
public $forceEntityHydrationFromInput   = true;
public $autoPurgeRedundantAttributes    = true;
// Auto hash passwords
public static $passwordAttributes  = array('password');
public $autoHashPasswordAttributes = true;

protected $table  = 'users';
protected $guarded  = array('id','created_at','updated_at');
protected $hidden = array('password');
protected $fillable = array('first_name','last_name','employee_id','position','email','password');

public static $rules = array(
    'first_name'            => 'required',
    'last_name'             => 'required',
    'employee_id'           => 'required|max:10',
    'position'              => 'required',
    'email'                 => 'required|email|unique',
    'password'              => 'required|alpha_num|min:6',
);

Controller:

public function update($id)
{
    $user = User::find($id);
    // Check if a password has been submitted
    if(!Input::has('password')){
    // If so remove the validation rule
      $user::$rules['password'] = '';
    // Also set autoHash to false;
      $user->autoHashPasswordAttributes = false;
    }
    // Run the update passing a Dynamic beforeSave() closure as the fourth argument
    if($user->updateUniques(
      array(),
      array(),
      array(),
      function($user){
    // Check for the presence of a blank password field again
        if(empty($user->password)){
    // If present remove it from the update
          unset($user->password);
          return true;
        }
      })
    ){
      Alert::success('User Updated')->flash();
      return Redirect::route('admin.users.index');
    }
        Alert::add('form','true')->flash();
    return Redirect::back()
      ->withInput(Input::except('password'))
      ->withErrors($user->errors());
}


来源:https://stackoverflow.com/questions/21314130/laravel-ardent-user-model-editing-saving

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!