Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update hasMany relationship in Laravel 5.1

I am totally new on Laravel, and I have implement the User table provided by Laravel Auth, and also I have create a table for the user meta data that is a Key Value pare table.

The user meta table is created by the following code :

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UserMeta extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('user_meta', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->char('meta_key', 255);
            $table->longText('meta_value')->nullable();
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('user_meta');
    }
}

In my User model I have the following method:

public function meta() {
    return $this->hasMany('App\Models\UserMeta');
}

and inside my UserMeta model I have the following method:

public function user() {
    return $this->belongsTo('App\User');
}

Until now anything is fine. So, when I register a new user I perform the following actions:

$user = User::create(
    [
        'name'     => $data['name'],
        'email'    => $data['email'],
        'password' => bcrypt( $data['password'] ),
    ]
);

if ( $user ) {

    $telephone_number = new UserMeta;
    $telephone_number->user()->associate($user);
    $telephone_number->meta_key = 'telephone_number';
    $telephone_number->meta_value = $data['telephone_number'];
    $telephone_number->save();

    $company = new UserMeta;
    $company->user()->associate($user);
    $company->meta_key = 'company';
    $company->meta_value = $data['company'];
    $company->save();

    $web_site = new UserMeta;
    $web_site->user()->associate($user);
    $web_site->meta_key = 'web_site';
    $web_site->meta_value = $data['web_site'];
    $web_site->save();

}

return $user;

I suppose that should be a better way to perform that same actions, but I don't know what is the other way :( :)

So, the above code works very nice for me, but now the problem is with the value update. In this case, how can I update the Meta Data when I update the user profile ?

In my update method of my UserControler, I perform the following actions:

$user = User::where( 'id', '=', $id )->first();

$user->name  = $request->input( 'name' );
$user->email = $request->input( 'email' );
$user->password = bcrypt( $request->input( 'password' ) );

$user->save();

My $request->input(); has the following extra fields that corresponding to meta values telephone_number, web_site, company.

So, how can I update the meta values in the user_meta table ?

like image 238
KodeFor.Me Avatar asked Jun 24 '15 10:06

KodeFor.Me


People also ask

Which method is used to update data in laravel?

We can update the records using the DB facade with update method. The syntax of update method is as shown in the following table. Run an update statement against the database.

How to define relationship in laravel?

To define a relationship, we need first to define the post() method in User model. In the post() method, we need to implement the hasOne() method that returns the result. Let's understand the one to one relationship through an example. First, we add the new column (user_id) in an existing table named as posts.


1 Answers

Looping through values

Firstly, you are right that you could loop through the three keys in your create method to:

// Loop through all the meta keys we're looking for
foreach(['telephone_number', 'web_site', 'company'] as $metaKey) {
    $meta = new UserMeta;
    $meta->meta_key = $metaKey;
    $meta->meta_value = array_get($data, $metaKey);
    $meta->save();
}

The Update Method: Approach One

Then, in your update method

// Loop through all the meta keys we're looking for
foreach(['telephone_number', 'web_site', 'company'] as $metaKey) {
    // Query for the meta model for the user and key
    $meta = $user->meta()->where('meta_key', $metaKey)->firstOrFail();
    $meta->meta_value = array_get($data, $metaKey);
    $meta->save();
}

Note the firstOrFail() to end the query. This is just me being strict. If you wanted to add a meta value if it didn't exist, then you could replace that line with

// Query for the meta model for the user and key, or
// create a new one with that key
$meta = $user->meta()->where('meta_key', $metaKey)
    ->first() ?: new UserMeta(['meta_key' => $metaKey]);

The Update Method: Approach Two

This approach is a little more efficient, but a more complex (but also potentially teaches about a cool feature of Eloquent!).

You could load in all of the meta keys first (see lazy eager loading).

// load the meta relationship
$user->load('meta');

// Loop through all the meta keys we're looking for
foreach(['telephone_number', 'web_site', 'company'] as $metaKey) {
    // Get the first item with a matching key from the loaded relationship
    // Or, create a new meta for this key
    $meta = $user->meta
        ->first(function($item) use ($metaKey) { 
            return $item->meta_key === $metaKey; 
        }) ?: new UserMeta(['meta_key' => $metaKey]);
    $meta->meta_value = array_get($data, $metaKey);
    $meta->save();
}
like image 78
stef Avatar answered Nov 14 '22 13:11

stef