Why trait for auto generated column is not working?

i have this trait to generate asset_code but I got this error instead
SQLSTATE[HY000]: General error: 1364 Field 'asset_code' doesn't have a default value
SQLSTATE[HY000]: General error: 1364 Field 'asset_code' doesn't have a default value
The model
class Asset extends BaseModel
{
use AssetCode;
class Asset extends BaseModel
{
use AssetCode;
the trait AssetCode.php
<?php

namespace App\Models\Traits;

trait AssetCode
{
public static function bootAssetCode(): void
{
static::creating(function ($model) {
if (empty($model->asset_code)) {
$model->asset_code = self::generateAssetCode();
}
});
}

protected static function generateAssetCode(): string
{
return 'ASSET-' . strtoupper(uniqid());
}
}
<?php

namespace App\Models\Traits;

trait AssetCode
{
public static function bootAssetCode(): void
{
static::creating(function ($model) {
if (empty($model->asset_code)) {
$model->asset_code = self::generateAssetCode();
}
});
}

protected static function generateAssetCode(): string
{
return 'ASSET-' . strtoupper(uniqid());
}
}
5 Replies
Povilas Korop
Povilas Korop3w ago
My first guess: asset_code is not in the $fillable of the Model? If it's not the correct guess, put dd() in the Trait to check if it's even called at all.
Jerome V
Jerome VOP3w ago
Hi sir, I followed you in youtube.. anyways, the asset_code is fillable and I tried also dd() and the trait is not triggered.. may I can't use two trait in one event? Since the model is extends BaseModel and inside of it has trait tor timestamp BaseModel
<?php

namespace App\Models;

use App\Models\Contracts\Timestampable as TimestampableInterface;
use App\Models\Traits\Timestampable;
use Illuminate\Database\Eloquent\Model;

class BaseModel extends Model implements TimestampableInterface
{
use Timestampable;

public $timestamps = false;
}
<?php

namespace App\Models;

use App\Models\Contracts\Timestampable as TimestampableInterface;
use App\Models\Traits\Timestampable;
use Illuminate\Database\Eloquent\Model;

class BaseModel extends Model implements TimestampableInterface
{
use Timestampable;

public $timestamps = false;
}
then in the model I also call another trait for asset code
class Asset extends BaseModel
{
use AssetCode;
/**
class Asset extends BaseModel
{
use AssetCode;
/**
and in this case one of the trait is not triggered?
Povilas Korop
Povilas Korop3w ago
Interestin. I've never had such setup with layers. I guess that can be a problem with Laravel "magic" of automatic bootable traits.
Oscar Carvajal Mora
What is the implementation of your Timestampable trait? I just code a similar implementation to test and works fine for me: Asset Model:
<?php

namespace App\Models;

use App\Traits\HasCode;

class Asset extends Model
{
use HasCode; // Use the Trait
}
<?php

namespace App\Models;

use App\Traits\HasCode;

class Asset extends Model
{
use HasCode; // Use the Trait
}
Custom model (only extend from Laravel model):
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model as BaseModel;

class Model extends BaseModel {}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model as BaseModel;

class Model extends BaseModel {}
HasCode trait implementation:
<?php

namespace App\Traits;

use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;

trait HasCode
{
protected static function bootHasCode(): void
{
static::creating(function (Model $model) {
$columnName = static::getModelColumnName();

if (empty($model[$columnName])) {
$model[$columnName] = static::generateCode();
}
});
}

protected static function generateCode(): string
{
return Str::upper(Str::random(8));
}

protected static function getModelColumnName(): string
{
return 'code';
}
}
<?php

namespace App\Traits;

use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Model;

trait HasCode
{
protected static function bootHasCode(): void
{
static::creating(function (Model $model) {
$columnName = static::getModelColumnName();

if (empty($model[$columnName])) {
$model[$columnName] = static::generateCode();
}
});
}

protected static function generateCode(): string
{
return Str::upper(Str::random(8));
}

protected static function getModelColumnName(): string
{
return 'code';
}
}
I tested ir running on Tinker App\Models\Asset::create([])
Jerome V
Jerome VOP3w ago
The senior dev implement this.. its ok now but different approach on trait instea of using boot<trait_name>() they use initialize<trait_name>() but this is temporary fix for now so Basically BaseModel is another layer where it's extend the model and use another trait
<?php

namespace App\Models;

use App\Models\Contracts\Timestampable as TimestampableInterface;
use App\Models\Traits\Timestampable;
use Illuminate\Database\Eloquent\Model;

class BaseModel extends Model implements TimestampableInterface
{
use Timestampable;

public $timestamps = false;
}
<?php

namespace App\Models;

use App\Models\Contracts\Timestampable as TimestampableInterface;
use App\Models\Traits\Timestampable;
use Illuminate\Database\Eloquent\Model;

class BaseModel extends Model implements TimestampableInterface
{
use Timestampable;

public $timestamps = false;
}
Your implementation is working in another project without another layer

Did you find this page helpful?