Laravel - Eloquent attach() not working for models - php

TL;DR
Trying to get three models to interact using eloquent for a rest api.
User - belongsToMany(pulls)
Pull - belongsToMany(user) && belongsToMany(boxes)
Box - belongsToMany(pulls)
The pull_user table is working perfectly, I can just attach a user after I save a pull. Saving a box works fine but the attach doesn't work/enter anything into the pivot table (I get no errors though).
The Problem
I can't get a pivot table that associates two of my models together to attach() after a save. I have the three models listed above, the pivot is working for pull_user but not for pull_box even though the save for box is working perfectly. I am able to save a box without an error but the association just never occurs (no error).
The Code
pull_box.php
class PullBox extends Migration
{
public function up()
{
Schema::create('pull_box', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('pull_id');
$table->integer('box_id');
});
}
public function down()
{
Schema::dropIfExists('pull_box');
}
}
Pull.php
class Pull extends Model
{
protected $fillable = ['from', 'to', 'runit_id', 'start_time', 'end_time', 'box_count', 'pull_status', 'audit_status', 'status', 'total_quantity', 'accuracy'];
public function users(){
return $this->belongsToMany('App\User');
}
public function boxes(){
return $this->belongsToMany('App\Box');
}
}
Box.php
class Box extends Model
{
protected $fillable = ['user_id','from', 'to', 'runit_id', 'start_time', 'end_time', 'pull_id', 'total_quantity', 'status', 'accuracy'];
public function pulls(){
return $this->belongsToMany('App\Pull');
}
}
BoxController.php
public function store(Request $request)
{
$this->validate($request, [
'user_id' => 'required|integer',
...
]);
$user_id = $request->input('user_id');
...
$box = new Box([
'user_id' => $user_id,
...
]);
$pull = Pull::whereId($pull_id)->first();
if($box->save()){
$pull->boxes()->attach($box->id);
$box->view_box = [
'href' => 'api/v1/box/' . $box->id,
'method' => 'GET'
];
$message = [
'msg' => 'Box created',
'box' => $box,
'pull' => $pull_id
];
return response()->json($message, 201);
}
$response = [
'msg' => 'Box creation error, contact supervisor',
];
return response()->json($response, 404);
}
The Solution
I need to know how I can get this association working. I am going to need to add a new layer in under the pull for Item, but I don't want to move one before I solve this. I think that my problem has to stem from a syntactical/logical error on my part but I can't see it. There are a bunch of questions on SO that are very close to giving me a solution, but after reading them I wasn't able to solve my problem.
Any help is appreciated.

Try renaming your pull_box table to box_pull, pivot tables on laravel must be in alphabetical order. If you want to use custom name on pivot table you have to extends your pivot, for example:
<?php
namespace App;
use Illuminate\Database\Eloquent\Relations\Pivot;
class PullBox extends Pivot
{
protected $table = 'pull_box';
}
And your many to many relationships:
class Pull extends Model
{
protected $fillable = ['from', 'to', 'runit_id', 'start_time', 'end_time', 'box_count', 'pull_status', 'audit_status', 'status', 'total_quantity', 'accuracy'];
public function users(){
return $this->belongsToMany('App\User');
}
public function boxes(){
return $this->belongsToMany('App\Box')->using('App\PullBox');
}
}
class Box extends Model
{
protected $fillable = ['user_id','from', 'to', 'runit_id', 'start_time', 'end_time', 'pull_id', 'total_quantity', 'status', 'accuracy'];
public function pulls(){
return $this->belongsToMany('App\Pull')->using('App\PullBox');
}
}

Related

Laravel PUT relationship

Fiddling with Laravel and coming from Symfony, I'm trying to replicate some code.
I'm trying to PUT a Suggestion model (overwritting anything, even relationships) and wanted to know the proper way to overwrite the model.
Since tags attribute in fillable doesn't exist, I certainly get an error (Undefined column: 7 ERROR: column "tags" of relation "suggestions" does not exist).
Suggestions and tags both have their own tables and a pivot table that contains two foreign keys to both tables id.
Request & Response :
{
"id":2,
"content":"Magni.",
"tags":[{"id":13,"name":"MediumAquaMarine"}]
}
{
"id":2,
"content":"Magni.",
"tags":[{"id":10,"name":"Navy"},{"id":13,"name":"MediumAquaMarine"}]
}
public function update(Request $request, Suggestion $suggestion)
{
$validator = Validator::make($request->all(), [
'content' => 'required',
'tags.id' => 'numeric',
]);
if ($validator->fails()) {
return response()->json($validator->messages(), Response::HTTP_BAD_REQUEST);
}
$suggestion->fill($request->only($suggestion->getFillable()))->save();
return new SuggestionResource($suggestion);
}
class Suggestion extends Model
{
use HasFactory;
protected $fillable = ['content', 'tags'];
protected $with = ['tags'];
public function tags()
{
return $this->belongsToMany(Tag::class, 'suggestions_tags')->withTimestamps();
}
}
class Tag extends Model
{
use HasFactory;
protected $hidden = ['pivot'];
public function suggestions()
{
return $this->belongsToMany(Suggestion::class, 'suggestions_tags')->withTimestamps();
}
}
You could just pass an array of IDs for tags instead of the whole object.
Do:
"tags":[10, 13]
Instead of:
"tags":[{"id":10,"name":"Navy"},{"id":13,"name":"MediumAquaMarine"}]
Change the validation rules accordingly and then you can remove tags from $fillable and do something like:
$suggestion->update($request->validated());
$suggestion->tags()->sync($request->tags);

Many to many relationship with more than 2 tables in Laravel

I'm trying to implement a many-to-many relationship with more than two tables in Laravel.
Migration For Relationship Table
public function up()
{
Schema::create('lab_form_detail', function (Blueprint $table) {
$table->unsignedBigInteger('color_id');
$table->unsignedBigInteger('lab_form_id');
$table->unsignedBigInteger('pontics_design_id');
$table->unsignedBigInteger('teeth_design_id');
$table->integer('quantity');
$table->string('teeth_number');
$table->foreign('lab_form_id')->references('id')->on('lab_forms');
$table->foreign('color_id')->references('id')->on('colors');
$table->foreign('pontics_design_id')->references('id')->on('pontics_designs');
$table->foreign('teeth_design_id')->references('id')->on('teeth_designs');
});
}
Lab Form Model
class LabForm extends Model
{
use HasFactory;
public $timestamps = false;
public function colors()
{
return $this->belongsToMany(Color::class, 'lab_form_detail', 'lab_form_id', 'color_id')
->withPivot([
'pontics_design_id',
'teeth_design_id',
'quantity',
'teeth_number'
]);
}
public function ponticsDesigns()
{
return $this->belongsToMany(PonticsDesign::class, 'lab_form_detail', 'lab_form_id', 'pontics_design_id')
->withPivot([
'color_id',
'teeth_design_id',
'quantity',
'teeth_number'
]);
}
public function teethDesigns()
{
return $this->belongsToMany(TeethDesign::class, 'lab_form_detail', 'lab_form_id', 'teeth_design_id')
->withPivot([
'color_id',
'pontics_design_id',
'quantity',
'teeth_number'
]);
}
}
I also use belongsToMany for other related models.
When I try to insert a new row, I need to use functions for the relationship to insert.
For example:
$lf = LabForm::find(1);
$lf->colors()->attach(1, [
'pontics_design_id' => 2,
'teeth_design_id' => 1,
'quantity' => 10,
'teeth_number' => '30 to 40'
]);
As you can see, when inserting a new row, I need to use one of colors, teethDesigns, ponticsDesigns. Also, I need to insert values differently which depend on the functions that define the relationship.
My question is, can I combine related values into one function and insert them all at the same time? Like:
public function labFormDetail()
{
// insert all values at once
'lab_form_id', 'pontics_design_id', 'color_id', 'teeth_design_id','quantity', 'teeth_number'
}
Or should I create a model for this relationship table?
Or you may suggest your approach for this kind of relationship.

Data not Saving into pivot table using Laravel Api Resource

please I am new to Laravel, I want to use Laravel API Resource to store database inside database.
I have 3 Tables
Users
Category
Category_User (this is a pivot table)
In my Controller (OnboardsControllers), I have this to store data
public function store(Request $request)
{
$category_user = Category_User::firstOrCreate(
[
'user_id' => $request->user()->id,
'category_id' => $request->$category->id,
],
);
return new CategoryUserResource($category_user);
}
In my CategoryUserResource I have this
public function toArray($request)
{
return [
'user_id' => $this->user_id,
'category_id' => $this->category_id,
'created_at' => (string) $this->created_at,
'updated_at' => (string) $this->updated_at,
];
In my Pivot Table, I have this
public function up()
{
Schema::create('category_user', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('category_id')->unsigned();
$table->integer('user_id')->unsigned();
$table->timestamps();
});
}
In my model, I added this
protected $fillable = [
'user_id', 'category_id',
];
In my route/api
Route::post('/category_user', 'OnboardsController#onboardupdate');
I believe the error is here
'user_id' => $request->user()->id,
When I removed it, it didn't returned any error
When I tried to save to my database using Postman to test, it not saving. Please, I don't know what I am doing wrong.
Thanks
To be honest, you do not need a model Category_User (but you need a table).
In Laravel a more concise approach is used:
public function store(Request $request)
{
$user = User::find($request->input('user_id'));
$user->categories()->attach($request->input('category_id'));
}
Also I'm not sure if you have declared a method categories() in model User:
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
I also strongly doubt the existence of method user() of class Request.
If the request parameter has a name category_id, then you need to access it like this:
$request->input('category_id');

Display table data without user auth

I'm studying event message board. I can display table data by every Users own post. however I would like to display All post too. I wrote this as $tasksall but it didn't work. Could someone teach me what is wrong?
AController.php
public function index()
{
$tasks = Auth::user()
->tasks()
->orderBy('is_complete')
->orderByDesc('created_at')
->paginate(5);
$tasksall =
->tasks()
->orderBy('is_complete')
->orderByDesc('created_at')
->paginate(5);
return view('tasks', [
'tasks' => $tasks, 'tasksall' => $tasksall
]);
}
Task.php (model)
class Task extends Model
{
protected $casts = [
'is_complete' => 'boolean',
];
protected $fillable = [
'title',
'is_complete',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
AController.php I add this code
public function person()
{
return $this->belongsTo('App\Models\Task');
}
public function getData()
{
return $this->id . ':'/ $this->person->name.')';
}
index.blade.php I add this code
{{ $task2->getData() }}
You can just write a query to get all the task using eloquent to get all the tasks.
$tasksall = Task::all();
Have a look at this link.
Also for you case I think the problem is you are getting task from the User model so you $task will contain only task related to that particular user as you have a belongsTo relation of task with user.
For Your case to get name of User from task.
//Task model
class Task {
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
}
Then you can query like this in your controller.
$task = Task::find($id);
$name = $task->user->name;

Add values to pivot table laravel

When I want to save a reaction to a ticket I've three tables (in laravel):
-Tickets
-Reaction
-Reaction_Tickets (pivot table)
When I want to save a reaction I do it like this:
public function addReaction(Request $request, $slug)
{
$ticket = Ticket::whereSlug($slug)->firstOrFail();
$reaction = new reactions(array(
'user_id' => Auth::user()->id,
'content' => $request->get('content')
));
return redirect('/ticket/'.$slug)->with('Reactie is toegevoegd.');
}
But now of course it's not added to the pivot table. And I can't add it because I don't have a model of it. What's the right way of doing this?
EDIT:
-Tickets
public function reactions()
{
return $this->belongsToMany('App\reactions');
}
-Reactions
public function tickets()
{
return $this->hasOne('App\tickets');
}
From the Laravel documentation, you need to save and attach the Reaction to the Ticket:
$reaction = new reactions(array(
'user_id' => Auth::user()->id,
'content' => $request->get('content')
));
$reaction->save(); // Now has an ID
$tickets->reactions()->attach($reaction->id);
In your Ticket model, you need to have the relationship defined:
class Ticket extends Model {
protected $table = "tickets";
public function reactions(){
return $this->belongsToMany("App\Reaction");
}
}
And you should have the inverse defined on Reaction:
class Reaction extends Model {
protected $table = "reactions";
public function tickets(){
return $this->belongsToMany("App\Ticket");
}
}
If your models are set-up like so, you shouldn't have any issue attaching the new Reaction to your existing Ticket via your pivot table.

Categories