PHP / Laravel - One Model with multiple polymorphic relations - php

In my web app, users will be able to save some parsed content to a table called field_results.
However, this model needs to reference two polymorphic relationships:
FieldResults.php:
// A field result morphs to either a document field or email field.
public function fieldable()
{
return $this->morphTo();
}
// A field result morphs to either a document or email.
public function typeable()
{
return $this->morphTo();
}
The fieldable refers to:
DocumentFields
EmailFields
and the typeable refers to:
Documents
Emails
In my DocumentField and EmailField models, I have defined this relationship:
// A field will have a final result.
public function result()
{
return $this->morphOne(FieldResult::class, 'fieldable');
}
And in my Document and Email models, I have defined this:
public function results()
{
return $this->morphMany(FieldRuleResult::class, 'typeable');
}
So consider below loop, where I need to save some content, that will reference a specific documentfield/emailfield and a specific document/email.
foreach ($document->fields as $field) {
$content = $field->content->text;
//Save the content to `FieldResult
$field->result()->create(['content' => $content]);
}
Above will only set the values for the fieldable morph:
SQLSTATE[HY000]: General error: 1364 : Field 'typeable_type' doesn't have a default value [...]
If I change it to save to the document instead, I get below error::
//Save the content to `FieldResult
$document->result()->create(['content' => $content]);
SQLSTATE[HY000]: General error: 1364 Field 'fieldable_type' doesn't have a default value [...]
How can I do, so my model FieldResult can have two polymorphic relationships?

You can solve this problem by replacing this line:
$field->result()->create(['content' => $content]);
By the following lines:
$field->result()->create([
'content' => $content,
'typeable_id' => $document->id,
'typeable_type' => get_class($document),
]);

Related

How to add pivot table when inserting data to database in Laravel 8

maybe someone know how to insert pivot table in Laravel 8 automatically every i insert counselings table?
I have Model Counseling n to n Problem,
Input form
counselings table
problems table
Counselings Model
Problem Model
Controller
public function create()
{
return view('admin.counseling.create', [
'title' => 'Tambah Bimbingan dan Konseling',
'students' => Student::all(),
'problems' => Problem::all()
]);
}
public function find_nis(Request $request)
{
$student = Student::with('student_class', 'counselings')->findOrFail($request->id);
return response()->json($student);
}
public function store(Request $request)
{ dd($request->all());
$counseling = new Counseling();
$counseling->student_id = $request->student_id;
$counseling->user_id = Auth::user()->id;
$counseling->save();
if ($counseling->save()) {
$problem = new Problem();
$problem->id = $request->has('problem_id');
$problem->save();
}
}
You can insert into a pivot table in a few different ways. I would refer you to the documentation here.
Attaching
You may use the attach method to attach a role to a user by inserting
a record in the relationship's intermediate table:
Example:
$problem->counselings()->attach($counseling->id);
Sync
You may also use the sync method to construct many-to-many
associations. The sync method accepts an array of IDs to place on the
intermediate table. Any IDs that are not in the given array will be
removed from the intermediate table.
Example:
$problem->counselings()->sync($counselingsToSync);
Toggle
The many-to-many relationship also provides a toggle method which
"toggles" the attachment status of the given related model IDs. If the
given ID is currently attached, it will be detached. Likewise, if it
is currently detached, it will be attached:
Example:
$problem->counselings()->toggle($counselingsToToggle);
I would change your store() method to something like this :
public function store(Request $request)
{
$counseling = Counseling::create([
'student_id' => $request->student_id,
'user_id' => Auth::user()->id
]);
if($request->has('problem_id'){
$counseling->problems()->attach($request->problem_id);
//return something if problem id is in request
}
//return something if problem id is not there
}

Laravel call to a member function addEagerConstraints() on float

I'm trying to get sum of columns in relationship model but i get this error
Call to a member function addEagerConstraints() on float
Code
model
public function cableLentgh()
{
return $this->links()->sum('cable_length');
}
Logic
my model has relationship to link model like this
public function links()
{
return $this->hasManyThrough(Link::class, Segment::class, 'hthree_id', 'segment_id');
}
in links table I have column named cable_length where numbers are stored
now I want to have SUM of those numbers.
Any idea?
Update
full error detail
exception: "Error"
file: "C:\laragon\www\web\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Builder.php"
line: 578
message: "Call to a member function addEagerConstraints() on float"
If you relationship is correct then you should get the collection of links by the following call:
$this->link;
If it returns the collections, you can then run sum method of collection as below:
public function cableLentgh()
{
return $this->links->sum('cable_length'); //Notice () removed
}
I know this might not be the exact answer for your problem as you are trying to get the sum by query which is better option. As it's not working, then using collection is also an option that may solve your problem.
For me you should use the variable, and not the function link :
public function cableLentgh()
{
return $this->links->sum('cable_length');
}
I think it has something to do with the relationship ids',I would try to specify like in hasManyThrough documentation
class Country extends Model
{
public function posts()
{
return $this->hasManyThrough(
'App\Post',
'App\User',
'country_id', // Foreign key on users table...
'user_id', // Foreign key on posts table...
'id', // Local key on countries table...
'id' // Local key on users table...
);
}
}

Laravel attach pivot data without errors

I a have pivot table and a relation on model Product:
public function product_bodies()
{
return $this->belongsToMany(static::class, 'product_bodies')->withPivot('product_id', 'product_body_id');
}
In the controller when I want to attach data:
$products = ['sadasdasd', 'asdasda', 'asdasd', 'asdasd']; //for column product_body_id
$product = Product::create($request->all());
$product->product_bodies()->attach($products);
I get the error:
General error: 1364 Field 'product_body_id' doesn't have a default
value
If I do this:
public function product_bodies()
{
return $this->belongsToMany(static::class, 'product_bodies', 'product_id', 'product_body_id')->withPivot('product_id', 'product_body_id');
}
Then all works well. But then I can't get pivot data with:
$product->product_bodies;
I get empty items..
How can I fix this problem?
Table product_bodies has 3 columns:
id
product_id
product_body_id
In product_body_id I pass strings.
I have 3 ideas:
You need to replace static::class to '\App\ProductBody' or ProductBody::class
public function product_bodies()
{
return $this->belongsToMany('\App\ProductBody', 'product_bodies')->withPivot('product_id', 'product_body_id');
}
$products must be array of product bodies ids.
$productBodiesIds = [1, 55, 66];
$product->product_bodies()->attach($productBodiesIds);
Maybe, sync instead of attach will be a better solution.

Relation two tables in Yii2

I have made relation between Buku and Guest. I want to add link download ebook in guest's email. Field link_dl in table Buku.
In common\models\Buku
public function getGuest()
{
return $this->hasOne(Guest::className(), ['id_buku' => 'id_buku']);
}
In common\models\Guest
public function getBuku()
{
return $this->hasMany(Buku::className(), ['id_buku' => 'id_buku']);
}
In Controller
if($model->load(Yii::$app->request->post()))
{
$value = Yii::$app->mailer->compose()
->setFrom('myaccount#gmail.com')
->setTo($model->email)
->setSubject('Download Ebook')
->setTextBody($model->buku->link_dl) //link download ebook $model->relationName->field_name
->send();
$model->save();
But I get an error,
exception 'yii\base\ErrorException' with message 'Trying to get property of non-object'
What is the issue in here? Thankyou. It's Solved
Your relation getBuku is declared as One-to-Many, so when you access buku with $model->buku you get array of Buku models.
If it's really a relation of type One-to-Many you have to choose (with any kind of logic, or simple get the 0 index) the Buku model you need like:
->setTextBody($model->buku[0]->link_dl)
If the relation suppose to be One-to-One, you need to change the relation in Guest model and then to access link_dl as in your code:
// common\models\Guest
public function getBuku()
{
return $this->hasOne(Buku::className(), ['id_buku' => 'id_buku']);
}
// Controller
->setTextBody($model->buku->link_dl)

Yii2 - How to get field value from relation

I have a table which has different types of text data from different sources, identified by type, lang, sourceId and stored in field text. Is there anyway to return by active record relation not object of table but only value of field text in oher words scalar query via relation?
Example: For now I have:
$modelName->RelationName->text) //field name storing expexted data, returns string.
Desired way is:
$modelName->RelationName//text field value returned only.
Yes But using lazy loading approach :
Update Your Relation as
public function getRelationName(){
//Related model Class Name
//related column name as select
return $this->hasOne(RelationClass::className() ,['id' => 'id'])->select('name')->scalar();
}
then get relation value as : -
$modelName->relationName//text field value returned only.
Extend your model with one or more getter for retrive the value you need using a relation eg:
In the model you need retrive the related data you can build a funtion for define the raltion (in this case an hasOne)
*/
public function getRelationName()
{
return $this->hasOne(ModelOfTheRelation::className(), ['column1' => 'column1', 'EvColumn2' => 'Evcolumn2']);
}
Then you can use getter function for the data
/* Getter f */
public function getRelatioName_field()
{
return $this->relationName->field;
}
In view you can easy obtain the data using
echo $model->relationName_field
or in gridview (dataprovider)
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'relationName_field',
this link could be useful http://www.yiiframework.com/wiki/621/filter-sort-by-calculated-related-fields-in-gridview-yii-2-0/

Categories