Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

beertastic's avatar

Booted method stopped adding default value on 'creating'

I want to add user_id to a product when a user creates one. This is not working. I've added user_id to $fillable, but the generated SQL doesn't include it. The user_id is mapped via foreign key to the user table, if that matters here?

protected static function booted()
{
    static::creating(function ($product) {
        $product->user_id = Auth::id();
    });
}
0 likes
10 replies
bobbybouwmann's avatar

This is because you use booted. The value is not set after that model is done creating. Instead, you should be using booting here.

protected static function booting(): void
{
    static::creating(function ($product) {
        $product->user_id = Auth::id();
    });
}
1 like
beertastic's avatar

that's interesting, I'll go read up on that! Cheers for the prompt reply!

I'm still getting this error, showing user_id is not even referenced:

Failed to create product: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`mydb`.`products`, CONSTRAINT `products_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)) (SQL: insert into `products` (`active`, `upsell_id`, `name`, `product_ref`, `intro`, `description`, `hidden`, `updated_at`, `created_at`) values (1, 0, 1111, 11, 11, 111, 0, 2020-07-03 08:39:46, 2020-07-03 08:39:46))

failing as it needs a user_id to satisfy the key requirements...?

beertastic's avatar

Out of interest, I was using Booted fine until this morning. Typical 'I've changed nothing and now it's broken' feeling.

Maybe I did... but I've changed nothing on the product side of things..

I can't find any docs online about booted or booting as Eloquent Model methods. I can find boot.. but that seems to be for older versions.

bobbybouwmann's avatar

Yeah, so booting and booted have been added in Laravel 7. The order is booting, boot, booted. If you need to set a column before saving you need to use booting.

Since you're setting the user_id you need to make sure this field is fillable inside your product model.

beertastic's avatar

it is in fillable yes. But still not being picked up.

Cheers for the 'boot' lesson! Very kind!

I'm still stuck and might just hard code it into my controller.. but I REALLY wanted to do things 'properly' on this project... :(

beertastic's avatar

My entire model

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Auth;

class Product extends Model
{  
use SoftDeletes;

protected $fillable = [
    'user_id',
    'active',
    'hidden',
    'name',
    'product_ref',
    'intro',
    'description',
    'upsell_id',
];

/**
 * @var mixed
 */
private $id;
/**
 * @var mixed
 */
private $user_id;
/**
 * @var mixed
 */
private $admin_grant_access;

public function affiliate()
{
    return $this->hasMany(Affiliate::class);
}

public function images()
{
    return $this->hasMany(ProductImages::class)->orderBy('sort_order');
}

public function orders()
{
    return $this->hasManyThrough(Order::class, Affiliate::class);
}

public function unpaidOrders()
{
    return $this->hasManyThrough( Order::class, Affiliate::Class)
        ->whereNull('order_payment_at');
}

public function defaultAffiliate()
{
    return $this->hasMany(Affiliate::class)
        ->where('is_default', 1);
}

public function paidOrders()
{
    return $this->hasManyThrough( Order::class, Affiliate::Class)
        ->whereNotNull('order_payment_at');
}

public function fulfilledOrders()
{
    return $this->hasManyThrough( Order::class, Affiliate::Class)
        ->whereNotNull('fulfullment_payment_at');
}

public function conversionRate()
{
    $orders = $this->orders()->count();
    $paid   = $this->paidOrders()->count();
    $rate = ($orders > 0) ? round((($paid / $orders) * 100), 0) : 0;

    $config = config('camp.conversion_colors');
    foreach($config as $percent => $color) {
        if ($rate >= $percent) {
            return ['rate' => $rate, 'indicator' => $config[$percent]];
        }
    }

    return ['rate' => $rate, 'indicator' => $config[15]];
}

/**
 * The "booted" method of the model.
 *
 * @return void
 */
protected static function booted()
{
    static::creating(function ($product) {
        $product->user_id = Auth::id();
    });
}

protected static function booting(): void
{
    static::creating(function ($product) {
        $product->user_id = Auth::id();
    });
}

}

This fails to add user_id when calling Product::create()

beertastic's avatar

My controller:

public function store(Request $request)
{
    $request->validate([
        'name' => 'required',
        'description' => 'required',
        'image.*' => 'image'
    ]);

    $post_data = $this->prepProductData($request);
    try {
        $product = Product::create($post_data);

............

And my prepData Method:

private function prepProductData(Request $request)
{
    $post_data = $request->all();
    $post_data['active']    = isset($post_data['active']) ? 1 : 0;
    $post_data['hidden']    = isset($post_data['hidden']) ? 1 : 0;
    $post_data['upsell_id'] = isset($post_data['upsell_id']) ? 1 : 0;

    return $post_data;
}

I really can't see why user_id is not being passed to the SQL INSERT statement (as per error above)

beertastic's avatar

OK, if anyone is following, firstly, I'm sorry :)

I gave up and put the setter in my prepProdcutData method.

that's fine, I hate it, but it's fine :)

bobbybouwmann's avatar
Level 88

Well, it's not working because you have a private property called user_id. You don't need that property, because Laravel stores all model fields in the attributes array on the model. Laravel uses the magic __get and __set methods for working with columns. However, a property always goes before the magic method. If you remove the property it should work ;)

beertastic's avatar

Ah! i'll be honest, every time PHPStorm underlines a var, I've got into th BAD habit of hitting Shit Alt Enter to 'fix' it.

But it's not always needed, case in point here it seems. MANY MANY thanks for helping me.. every time I think 'yeah. I got this'.. I realize I've a lot to learn :)

Please or to participate in this conversation.