nikas's avatar
Level 2

Generating custom ID (Uuid) for Many to Many relationship pivot table

I want to use uuid as my primary key inside of pivot table (many to many relationship). But I could not found a way to catch creating hook or something like that in my pivot table to generate uuid.

How can I achieve my goal?

0 likes
5 replies
nikas's avatar
Level 2

@Cronix In that case developer used MySQL trigger to generate id field. I want to let Eloquent to do that. I have trait which is generating uuid for creating model hook.

    protected static function boot()
    {
        parent::boot();
        static::creating(function ($model) {
            if (empty($model->{$model->getKeyName()})) {
                $model->{$model->getKeyName()} = Uuid::generate()->string;
            }
        });
    }

But then i tried to hook that trait to my pivot table using pivot model via using method it does not fire up and I'm getting error in DB.

*Relationship method

    public function items()
    {
        return $this
            ->belongsToMany(Item::class)
            ->using(UserItem::class);
    }

*Pivot class

class UserItem extends Pivot
{
    use Uuids;

    /**
     * Indicates if the IDs are auto-incrementing.
     * @var bool
     */
    public $incrementing = false;

    /**
     * The "type" of the auto-incrementing ID.
     * @var string
     */
    public $keyType = 'string';
}

*Error

[PDOException]                                                                
  SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value 
nikas's avatar
Level 2

Found a hacky way to solve this problem by ovverriding fromRawAttributes method.

class UserItem extends Pivot
{
    use Uuids;

    /**
     * Indicates if the IDs are auto-incrementing.
     * @var bool
     */
    public $incrementing = false;

    /**
     * The "type" of the auto-incrementing ID.
     * @var string
     */
    public $keyType = 'string';

    /**
     * Create a new pivot model from raw values returned from a query.
     * @param  \Illuminate\Database\Eloquent\Model $parent
     * @param  array $attributes
     * @param  string $table
     * @param  bool $exists
     * @return static
     * @throws \Exception
     */
    public static function fromRawAttributes(Model $parent, $attributes, $table, $exists = false)
    {
        if (!$exists and !array_key_exists('id', $attributes)) {
            $attributes['id'] = Uuid::generate()->string;
        }
        return parent::fromRawAttributes($parent, $attributes, $table, $exists);
    }
}
2 likes
afraz's avatar

Create Custom Intermedia model for pivot table

//add below attributes

public $incrementing = false; 
protected $keyType = 'string';
protected $primaryKey = 'id';

//add below function in it

 public static function boot()
{
    parent::boot();
    self::creating(function ($model) {
        $model->id = (string) Uuid::generate(4);
    });
}

It will work then

1 like
lararara's avatar

Laravel 11 Updated Answer

Say the Many to Many was between Articles and Posts. Effectively, you're just specifiying the Pivot class, otherwise the pivot table would default to using auto-incrementing ids.

class ArticlePost extends Pivot
{
    use HasUlids;
}


class Article extends Model
{
    use HasUlids;

    public function articles(): BelongsToMany
    {
        return $this->belongsToMany(Post::class)
            ->using(ArticlePost::class);
    }
}

class Post extends Model
{
    use HasUlids;

    public function articles(): BelongsToMany
    {
        return $this->belongsToMany(Article::class)
            ->using(ArticlePost::class);
    }
}

Please or to participate in this conversation.