Mapping relationships to generic models in Datamapper for Codeigniter - codeigniter

I have a number of different models in a system backed by the Datamapper library for Codeigniter such as Posts and Pages and am interested in adding Likes and Comments to the system. The way I see it, Likes and Comments can apply to any sort of model that extends Datamapper. How would I go about defining such a relationship (keep Likes for any sort of model in the same table, as well as Comments)?

I tend to create separate tables for likes and comments. I usually create this sort of schema:
Likes
-----
id // autoincrement
obj // the related model (the name of the model that is being liked)
obj_id // the foreign key
user_id // the user id that liked the model object
created // timestamp
updated // timestamp
Then the comments table:
Comments
--------
id // autoincrement
obj // the related model (same as above)
obj_id // the foreign key
message // the comment itself
user_id // the user id that commented on the model object
created // timestamp
updated // timestamp

Related

laravel - how to deal with model of similar type

I am trying to model a company and its relevant employee strucutre. I have 3 tables (company, position, employee) as below, and company haveMany position, and employee haveMany position. Position belongs to company, and position belongs to employee.
However, different position have some common field like onboard date, but have some fields are different. Forexmaple, CEO has a gurantee employment period, while other position dont. Quite a number of field is different too for different position.
In that case, should I using polymorphic to model? but as the company has quite a number of different position, this will create quite a lot new table in the database.
Do you have any advice on how to model different positions?
Companies
id
Position
Positions
id
type [CEO, manager, director, clerk, etc]
company_id
employee_id
Onboard Date
Ceased Date
Employees
id
position id
In that case, should I using polymorphic to model? but as the company has quite a number of different position, this will create quite a lot new table in the database.
No, why would be?
First of all, it should be manyToMany relation and not oneToMany because if you have two companies both of those can have CEO (for example) position and if you set $position->belongsTo(Company::class); it couldn't work.
It is polymorph relation there with positions as polymorphic angle of that triangle.
You would need
// companies
id
name
// employees
id
name
// positions
id
name
// positionables
position_id
positionable_id
positionable_type
With this, your models would be
class Company extends Model
{
public function positions()
{
return $this->morphToMany(Position::class, 'positionable');
}
}
class Employee extends Model
{
public function positions()
{
return $this->morphToMany(Position::class, 'positionable');
}
}
class Position extends Model
{
public function companies()
{
return $this->morphedByMany(Company::class, 'positionable');
}
public function employees()
{
return $this->morphedByMany(Company::class, 'positionable');
}
}
It allows you to set positions, companies and employees separately. Meaning, From dashboard you can make some new positions that will be available on frontend from select options let's say. Of course you should allow company and to employee to create new position (I suggest) and not just to use existing one but it could be out of scope of this question now: in example, when (and if) company creates new position (instead of selecting existing ones from options list), you would first create that position and store it into positions table and then associate company with it. Also, when using this kind of chained inputs to DB don't forget to use DB transactions. Into positionables table you would set other fields important for each relation (onboard_date, ceased_date, etc).
Documentation is very good and consult it if something is not clear (I hope it is already).
Disclaimer: I don't know rest of your project business plan and rest of project's requirements but for these three entities this is the best structure you can go with. I have set just mandatory members to models and tables for this example. Also in offered answer, I presumed use of Laravel's naming convention that's blindly followd from docs and this repo.
If the fields have no relationship with other tables, one possible way is to have a key-value table to store those fields and values:
position_fields
- id
- position_id
- key
- value
You can hence store the fields in key and the respective value in value. Then you may overwrite the __get magic method in Position model e.g.
public function __get($key){
$position_field = $this->hasMany(PositionField::class)->where('key', $field)->first();
return !!$position_field ? $position_field->value : $this->getAttribute($key);
}

Retrieve values from related table foreign key using Eloquent

Sorry if the question isn't clear.. I'm not super fluent in databases.
I have three tables:
companies equipment parts
----------- ----------- -----------
id id id
name company_id equipment_id
Using Eloquent, how do I get a Collection of all the parts that belong to the company with id=1
I know you setup relationships in the model. So now I can get all a company's equipment ($myCompany->equipment), and all equipment's parts ($myEquipment->parts), but I'm not sure how to easily get values in the reverse direction two tables away.
Thanks!
Laravel has such a beautiful documentation and API for this very thing. Take a look at the hasManyThrough relationship.
So in your Company model add this:
/**
* Get all of the parts for the company.
*/
public function parts()
{
return $this->hasManyThrough('App\Part', 'App\Equipment');
}

Laravel Many to many relationship with custom key relation

Before you mark this question as duplicate, please see the details :) I have a problem related to many to many relationship with custom columns linking
I have following tables
Employees
-Id
-brink_id <----- This is third party id I am saving of employee
-name
Jobs
-id
-brink_id <----- This is third party id I am saving of job
-description
employee_job
-id
-brink_id <----- This is third party id I am saving of relationship for third party
-brink_employee_id
-brink_job_id
In Employee Model I have created relationship
public function jobs()
{
return $this->belongsToMany('App\Models\Job','employee_job','brink_employee_id','brink_job_id');
}
And in Jobs Model
/**
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function employees()
{
return $this->belongsToMany('App\Models\Employee','employee_job','brink_job_id','brink_employee_id');
}
Actually I want to have many to many relationship with brink_id in employees table and brink_id in jobs table presented as brink_employee_id, brink_job_id in employee_job table not with ID (primary columns of respective table).
But when I try to insert in pivot table using following, it always inserts employee ID rather than brink_id
$employee = Employee::with('jobs')->where('brink_id',$employeeJob['brink_employee_id'])->first();
$employee->jobs()->attach($employeeJob['brink_job_id'], ['is_active' => 1]);
For example if brink_id in employee table is 123456 and ID is 1, the above code in employee_table will store 1 in employee_brink_id rather than 123456.
Please let me know what I am doing wrong.
If you don't specify a different parent key and related key, it will default to your current model's primary key and the related model's primary key respectively.
Specify the parent key name as the 5th argument and the related key name as the 6th argument:
return $this->belongsToMany('App\Models\Employee', 'employee_job', 'brink_job_id', 'brink_employee_id', 'brink_id', 'brink_id');
However, I'd personally use the ids from your system and not the ids from a 3rd party system in your relationships.

Get back data from the pivot table when store a many-to-many relationship

I have a many-to-many relationship between projects and surveys. I can successfully create a relationship between a survey and a project with
$userSurvey = $project->surveys()->save($survey);.
This will create a new record inside the question_survey pivot table (The pivot table contains the columns id, question_id and survey_id.)
$userSurvey will receive the newly created survey model. Is there any way to receive also the id of the new record in the question_survey pivot table?
When retrieving many to many relationships, Laravel will automatically attach the pivot to the resulting Model, so in your case, $userSurvey will automatically have an attribute called pivot that holds, well, of course, the pivot.
But by default, that pivot attribute only holds the foreign keys, so in your case, the question_id and survey_id. If you have any other extra attributes,(in your case id), simply use the withPivot method, as follows.
public function surveys()
{
return $this->belongsToMany('App\Question', 'question_survey')
->withPivot('id');
}
Now you can access the id from the pivot table:
$userSurvey->pivot->id;
Bonus, if you think that the pivot word just does not fit your wording style, just use the as method in your relationship to customize the variable name of the pivot attribute.
public function surveys()
{
return $this->belongsToMany('App\Question', 'question_survey')
->as('question_survey')
->withPivot('id');
}
Now you can access the id from the pivot table:
$userSurvey->question_survey->id;

Model doesn't show up on relationship right after saving?

For example
$user->transactions()->save($transaction);
dump($transaction->id); // id: 4
dd($user->transactions); // last id is 3
The $transaction that is saved does not show up in $user->transactions. This is a polymorphic relationship.
When you save a model through a relationship, all Laravel does is set the appropriate foreign keys. It doesn't set the newly saved model to the relation or add it to a collection.
If you want the model with updated relations use the fresh function.
$user->transactions()->save($transaction);
$user = $user->fresh('transactions');
Edit answer updated following #JCLee's correction to assign the result of $user->fresh().

Resources