I'm currently trying to troubleshoot my way through duplicating an object with its appropriate relationships. I usually use Laravel's DD helper to see if I'm getting the right information, but in this instance, I don't think that it's being run when it hits the line in the method that gets executed.
Here's my controller method that's handling the duplication.
$copiedManagementSystem = $managementSystem->replicate();
$copiedManagementSystem->inspections->each(function($inspection) {
$copiedInspection = $copiedManagementSystem->inspections()->create([
'name' => $inspection->name,
'management_system_id' => $inspection->managementSystemId,
'pass_score' => $inspection->passScore,
'max_score' => $inspection->maxScore,
'order' => $inspection->order,
]);
dd($inspection); //I've placed the dd here but it doesn't work in any position, in any part of the each function.
$inspection->checks->each(function($check){
$copiedInspection->checks()->create([
'question' => $check->question,
'values' => $check->values,
'type' => $check->type,
'inspection_id' => $check->inspectionId,
'order' => $check->order,
]);
});
});
$copiedManagementSystem->save();
Here is the ManagementSystem's model with the inspections relationship
class ManagementSystem extends Model
{
protected $table = 'management_systems';
protected $fillable = ['name', 'description'];
public function inspections()
{
return $this->hasMany(Inspection::class);
}
}
This is the inspection's model with the relations
class Inspection extends Model
{
protected $table = 'inspections';
protected $casts = [
'order' => 'integer'
];
protected $fillable = [
'name',
'management_system_id',
'pass_score',
'max_score',
'order'
];
public function checks()
{
return $this->hasMany(Check::class);
}
public function managementSystem()
{
return $this->belongsTo(ManagementSystem::class);
}
}
And finally, here is the check model with its relations.
class Check extends Model
{
protected $table = 'checks';
protected $fillable = [
'question',
'values',
'type',
'inspection_id',
'order'
];
public function inspection()
{
return $this->belongsTo(Inspection::class);
}
public function answers()
{
return $this->hasMany(Answer::class);
}
}
I'd really appreciate any help :)
EDIT: So I've come across a strange occurrence. If I run the following:
dd($copiedManagementSystem->inspections->count();
It returns 0. But if I run:
dd($managementSystem->inspections->count());
It returns 12, which is the correct value.
Does anyone know why this happens? And if so, how can I fix the issue?
Thank you!
Since replicate() does not replicate the relations you could try something like this.
$copiedManagementSystem = $managementSystem->replicate()
foreach($managementSystem->inspections as $inspection) {
$copiedManagementSystem->inspections->attach($inspection->replicate())
}
It is pseudo code, if you want the original inspections linked remove the $inspection->replicate() call and just use $inspection
Same goes for any other relations $managementSystem might have.
Related
I am trying to make a POST request to add a showroom in the Laravel application. When I try to do it with Showroom model using Eloquent ORM , it shows 500 internal server error. But if I do it with DB query, then it successfully CREATE the showroom. I commented out the db query lines and apply dd debugging and found out table for Showroom Model is null.
This is my controller code -
public function store(ShowroomRequest $request)
{
$showroom = new Showroom([
"name" => $request->get('name'),
"address" => $request->get('address'),
"description" => $request->get('description'),
]);
dd($showroom);
$ret = $showroom->save();
// $name = $request->input('name');
// $address = $request->input('address');
// $description = $request->input('description');
// DB::table('showroom')->insert(
// ['name' => $name, 'address' => $address, 'description' => $description]
// );
return redirect()->route('back.showroom.index')->withSuccess(__('Showroom Added Successfully.'));
}
And this is my model -
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Showroom extends Model
{
protected $fillable = ['name', 'description', 'address'];
protected static $ordersModel = 'App\Models\Order';
protected static $reviewsModel = 'App\Models\Review';
public function Orders()
{
return $this->hasMany(static::$ordersModel, 'showroom_id');
}
public function Reviews()
{
return $this->hasMany(static::$reviewsModel, 'showroom_id');
}
}
Finally this is my db structure -
Can anyone help me to find out what went wrong here? Thanks in advance.
in controller can you assign static values instead of request->get, and see if it saves.
please let me what happens afterwards.
also assign name of table in model like this,
protected $table = 'tablename';
I have a belongTo relation, if join condition is matched then ok but when there is no data for this it returns null. In this case, I want it returns default value as I expected. This is what I try but it not success. Please help me?
class Task extends Model
{
use SoftDeletes;
protected $table = 'tasks';
protected $fillable = [
'name',
'description',
'project_id',
];
protected $with = ['project', 'status'];
// this is expected
public function getProjectAttribute($value)
{
return $value ?? ['id' => '', 'name' => ''];
}
/**
* #return App\Modules\Com\Models\Project
*/
public function project()
{
return $this->belongsTo(Project::class, 'project_id', 'id')->select(['id', 'name']);
}
}
With description attribute, I can override it but why I dont the same thing with project attribute? And how do I set where for project relation?
Like this Task::select(*)->project()->where('project.name', 'ABC');.
I've never used Laravel -- but... the documentation shows that you can set a default for belongsTo when using it for updating in order to avoid conditional checks. Perhaps it will work for selecting too.
You can try adding the default to the end of your call.
return $this->belongsTo(Project::class, 'project_id', 'id')
->select(['id', 'name'])
->withDefault([
'project_id' => 'project.name',
'id' => 'ABC',
]);
Source: https://laravel.com/docs/6.x/eloquent-relationships#default-models
or
You could do a conditional check:
public function project()
{
$return $this->belongsTo(Project::class, 'project_id', 'id')->select(['id', 'name']);
if( $return === null )
// return your default values
else
return $return;
}
I don't know what's wrong, but here's my script at my AppController.
function getData () {
$list_data = MyModel::all()->sortBy('id')->paginate(15);
$count_data = $list_siswa->count();
return view('pages.list', ['list' => $list_data, 'count' => $count_data]);
}
And here's my model
class MyModel extends Model {
protected $table = 'students';
protected $fillable = [
'id',
'name',
'class',
'gender',
'address'
];
}
Any idea? I think the problem is in my controller.
You must paginate a database query not a collection, therefore you must user orderBy instead of combining all with sortBy, I have tested the below code and can confirm it works
function getData () {
$list_data = MyModel::orderBy('id')->paginate(15);
$count_data = $list_data->count();
return view('pages.list', ['list' => $list_data, 'count' => $count_data]);
}
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');
}
}
I've got 2 models with a many-to-many relationship. I want to be able to set a specific attribute with an array of ids and make the relationship in the mutator like this:
<?php
class Profile extends Eloquent {
protected $fillable = [ 'name', 'photo', 'tags' ];
protected $appends = [ 'tags' ];
public function getTagsAttribute()
{
$tag_ids = [];
$tags = $this->tags()->get([ 'tag_id' ]);
foreach ($tags as $tag) {
$tag_ids[] = $tag->tag_id;
}
return $tag_ids;
}
public function setTagsAttribute($tag_ids)
{
foreach ($tag_ids as $tag_id) {
$this->tags()->attach($tag_id);
}
}
public function tags()
{
return $this->belongsToMany('Tag');
}
}
<?php
class Tag extends Eloquent {
protected $fillable = [ 'title' ];
protected $appends = [ 'profiles' ];
public function getProfilesAttribute()
{
$profile_ids = [];
$profiles = $this->profiles()->get([ 'profile_id' ]);
foreach ($profiles as $profile) {
$profile_ids[] = $profile->profile_id;
}
return $profile_ids;
}
public function profiles()
{
return $this->belongsToMany('Profile');
}
}
However the setTagsAttribute function isn't working as expected. I'm getting the following error: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'profile_id' cannot be null (SQL: insert intoprofile_tag(profile_id,tag_id) values (?, ?)) (Bindings: array ( 0 => NULL, 1 => 1, ))
You can't attach many-to-many relations until you've saved the model. Call save() on the model before setting $model->tags and you should be OK. The reason for this is that the model needs to have an ID that Laravel can put in the pivot table, which needs the ID of both models.
It looks like you're calling the function incorrectly or from an uninitialized model. The error says that profile_id is NULL. So if you're calling the function as $profile->setTagsAttribute() you need to make sure that $profile is initialized in the database with an ID.
$profile = new Profile;
//will fail because $profile->id is NULL
//INSERT: profile->save() or Profile::Create();
$profile->setTagsAttribute(array(1,2,3));
Additionally, you can pass an array to the attach function to attach multiple models at once, like so:
$this->tags()->attach($tag_ids);
You can also pass it the model instead of the ID (but pretty sure array of models won't work)
Try using the sync method:
class Profile extends Eloquent {
protected $fillable = [ 'name', 'photo', 'tags' ];
protected $appends = [ 'tags' ];
public function getTagsAttribute()
{
return $this->tags()->lists('tag_id');
}
public function setTagsAttribute($tag_ids)
{
$this->tags()->sync($tagIds, false);
// false tells sync not to remove tags whose id's you don't pass.
// remove it all together if that is desired.
}
public function tags()
{
return $this->belongsToMany('Tag');
}
}
Don't access the tags through the tags() function, rather use the tags property. Use the function name if you want to pop additional parameters onto the relationship query and the property if you just want to grab the tags. tags() works in your getter because you're using get() on the end.
public function setTagsAttribute($tagIds)
{
foreach ($tagIds as $tagId)
{
$this->tags->attach($tagId);
}
}