I have been struggling to make this happen, but every time I failed.
I have two models – Map and User, and both can have many Maps (or users, respectively). Thi thing is, map has a primary key slug
, while User has primary key id
.
Schemes:
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('password')->nullable();
$table->enum('role', AppEnumRole::toArray());
$table->timestamps();
});
Schema::create('maps', function (Blueprint $table) {
$table->string('name');
$table->string('slug')->primary();
$table->string('perex')->nullable();
$table->string('categories')->nullable();
$table->enum('company', AppEnumCompany::toArray());
$table->string('icon')->nullable();
$table->boolean('is_public')->default(false);
$table->boolean('bounds')->default(false);
$table->timestamps();
});
Schema::create('map_user', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
$table->string('map_slug');
$table->foreign('map_slug')->references('slug')->on('maps');
});
Map.php
class Map extends Model
{
protected $primaryKey = 'slug';
protected $keyType = 'string';
protected $fillable = [
'name',
'slug',
'perex',
'categories',
'company',
'icon',
'is_public',
'bounds',
];
public function suppliers(): Collection
{
return $this->hasMany(Supplier::class)->get();
}
public function users(): BelongsToMany
{
return $this->belongsToMany(User::class, 'map_user', 'map_slug', 'user_id');
}
}
User.php
class User extends Model
{
use HasFactory;
protected $fillable = [
'name',
'email',
'password',
];
public function maps(): BelongsToMany
{
return $this->belongsToMany(Map::class, 'map_user', 'user_id', 'map_slug');
}
}
When creating a new Map, I want to attach the user to it:
/**
* Store a newly created resource in storage.
*/
public function store(StoreMapRequest $request): RedirectResponse
{
$user = User::where('email', auth()->user()->getAuthIdentifier())->firstOrFail();
$map = Map::create([
'name' => $request->input('name'),
'slug' => $request->input('slug'),
'perex' => $request->input('perex'),
'categories' => $request->input('categories'),
'company' => $request->enum('company', Company::class),
'icon' => $request->input('icon'),
'is_public' => $request->boolean('isPublic'),
'bounds' => $request->boolean('bounds'),
]);
$map->users()->attach($user->id);
return to_route('admin.dashboard')->with('success', 'Map created!');
}
and on the ->attach()
method I get following error:
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`mapy-dek`.`map_user`, CONSTRAINT `map_user_map_slug_foreign` FOREIGN KEY (`map_slug`) REFERENCES `maps` (`slug`))
insert into
`map_user` (`map_slug`, `user_id`)
values
(0, 1)
Thank you for your help!
2
Answers
The problem was with the code that was attaching the map to the user. It looks like the model instance was not stored to the DB yet, thus user had nothing to attach, hence the error.
I fixed it with
and it works like a charm.
This is because in your table map_user you have a primary key, that consist of one column user_id (wrong), should be a composite key, consisting of two columns user_id and map_slug (correct).
https://laravel.com/docs/11.x/migrations
Example:
$table->primary([‘id’, ‘parent_id’]);
in your case it would be: