innerbot
3921
6
Eloquent

Eloquent Help: Generating Attribute Values Before Creating Record

Posted 4 years ago by innerbot

On my User model, I have several fields that need to be populated before the record is created. I don't think this can be done using the User::$attributes property, because you can't specify a method to set a default value.

I could trigger them manually, but that's no fun, and shouldn't be necessary anyway.

The field(s) are complex in the sense that I'm using OpenSsl to generate a key-pair that gets saved to the database. The user's account uses these keys for various activities inside of the app.

So, I created a UserObserver class, and am attempting to populate those attributes using the creating hook.

However, when tinkering, I'm getting the following error when I call User::Create():

Indirect modification of overloaded property has no effect

Can anyone help me figure out the best way to make this happen?

Here is my user class:

<?php namespace App;

use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;

use Carbon\Carbon;
use Hash;

class User extends Model implements AuthenticatableContract, CanResetPasswordContract {

    use Authenticatable, CanResetPassword;

    const STATUS_UNCONFIRMED = false;
    const STATUS_ACTIVE = true;

    const ROLE_ADMIN = 42;
    const ROLE_PUBLISHER = 1;

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'users';

    /**
     * Default values for attributes
     * @var  array an array with attribute as key and default as value
     */
    protected $attributes = [
            'status' => self::STATUS_UNCONFIRMED,
            'role_id' => self::ROLE_PUBLISHER,
        ];

    /**
     * Protected attributes that CANNOT be mass assigned.
     *
     * @var array
     */
    protected $guarded = [ 'id', 'role_id', 'status', 'remember_token' ];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['password', 'role_id', 'status', 'confirmation_code', 'private_key', 'public_key', 'remember_token'];

    /**
     * The attributes that are represented as dates
     *
     * @var array
     */
    protected $dates = ['last_login'];

    public function setPasswordAttribute( $pass ) {
    
        $this->attributes['password'] = Hash::make( $pass );
    
    }

}

And here is my UserObserver (registered in the EventServiceProvider boot method per Laravel Documentation):

<?php namespace App\Observers;

use Carbon\Carbon;

class UserObserver {

    private $user;


    public function creating( \App\User $model )
    {
        $this->user = &$model;

        $this->user->last_login = Carbon::now();

        $this->generateKeys();

        if( is_null($this->user->private_key) || is_null($this->user->public_key) )
            return false;

        $this->generateConfirmationCode();

        if( is_null($this->user->confirmation_code) )
            return false;

    }

    protected function generateKeys()
    {
        $pk_res = openssl_pkey_new( array(
            'private_key_bits' => 2048,
            'private_key_type' => OPENSSL_KEYTYPE_RSA
        ));

        openssl_pkey_export($pk_res, $this->user->private_key);

        $pubkey = openssl_pkey_get_details($pk_res);
        $this->user->public_key = $pubkey["key"];

        openssl_pkey_free($pk_res);
    }

    protected function generateConfirmationCode()
    {
        $this->user->confirmation_code = Hash::make( $this->user->email . time() );
    }

}

Still learning, here, so please let me know if I got it all wrong, haha. Thanks!

Please sign in or create an account to participate in this conversation.