Does eloquent pivot tables work for multi-word table names? - laravel

I have two multi-word models, let's call them FunkyModel and AnotherModel.
Will creating a pivot table named another_model_funky_model work?
The docs and examples I've come across all use single word model names like this: model A - User, model B - Address, and pivot table will then be address_user.

If you dive into the source code of the BelongsToMany relation function, you'll find that if you haven't provided a $table, the code will execute the function joiningTable. This uses the current model and the passed related class, snake cases the names and then puts them in alphabetical order of each other.
Simply said, no matter if you have a single word or a couple, the result will always be the 2 classes snaked, in alphabetical order. Note that the alphabetical order is applied by the default php sort.
Examples:
Department + Occupation > department_occupation
AwesomeModel + LessInterestingModel > awesome_model_less_interesting_model
Role + UserPermission > role_user_permission
You can even try and see what the auto-generated name is by simply calling the following:
(new Model)->joiningTable(OtherModel::class, (new OtherModel));

Yes it would work, you can also name it whatever you want, you just need to declare the table name in the relation (same goes for the foreign keys)
class FunkyModel
{
public function anotherModels()
{
return $this->belongsToMany(AnotherModel::class, 'pivot_table_name', 'funky_model_id', 'another_model_id');
}

Related

Get a field from another table in eloquent model as an attribute with a if logic

Laravel > models >
In a table I have a list of files and an attribute that can be override with a value stored on another table
file_index (id, ..., code)
file_index_override(id, file_index_id, override_code)
In the file_index model, I would like to have an attribute that take the override_code if exists and the code if not. This structure is needed to run some groupBy on it.
At the moment I did
public function getCodeAnyAttribute() {
return FileIndexOverride::whereFileIndexId($this->id)->first() ?
FileIndexOverride::whereFileIndexId($this->id)->first()->override_code : $this->code;
}
But it does a single sql order on each lines, which cost a lot!
Is there a way using the power of eloquent?

Laravel/Eloquent get all appointments from a polymorphic "member_id" through a appointment_members table

I have an appointments table and an appointment_members table and my users need to be able to get a collection of appointments by searching with a "member_id", which could be a Person, Incident or CustomerID. The appointment_members table has member_id and appointment_id columns, so the member_type (also a column) is irrelevant. This all set up by a previous dev and what is missing are the relationships on the Eloquent models. I'm just creating a simple GET route that needs to return any/all appointments by that member_id. Each row has one appointment, so if I were to pass in a member_id that returned 10 results, some could have appts and others not, but at the end of the day I just need a collection of appts that are related to that member_id. Here's a screenshot of the appointment_members table:
If I create a simple hasOne relationship to appointments on appointment_members:
public function appointments()
{
return $this->HasOne(Appointment::class, 'id', 'appointment_id');
}
I can get a collection of appointment_members with it's respective appointment, but not sure how I boil it down to just getting the appointments. One workaround I have is to use that HasOne and then pluck/filter the appointments:
$appointmentMembers = AppointmentMembers::where('member_id', $request->input('memberId'))->get();
$appointments = $appointmentMembers->pluck('appointments')->filter();
Curious if anyone might see a better way to go about this. Thanks!
I'm possibly not understanding, but I would probably take the simplest approach here if the member type is not important.
The table is already set up to handle either a belongsToMany or a morphMany, so create the relationship on the Member class (or if you don't have a parent member class, stick it on each of the types Person, Incident, etc. You can also do this via poly, of course, but this is a simple example to get what you need):
public function appointments()
{
return $this->belongsToMany(Appointment::class)->withPivot('member_type');
}
And then just query on the member object you need appointments for (having poly would make this one step):
$allAppointmentsForID = $member->appointments();
$appointments = $allAppointmentsForID->wherePivot('member_type', $whateverClassThisIS);
The above takes member_type into account. If this doesn't matter, you can just use the top line.
Your original db is setup to handle polymorphic relations, so if you wanted more than the appointment you can set it up this way as well. For now, you'll need to add the TYPE to the query to cover the different classes.
If the member type is important, polymorphic might be something like this on the Member class:
public function appointments()
{
return $this->morphMany(Appointment::class, 'memberableOrmember_typeOrWhatever');
}
Then you can query on the member object with just one line
$appointments = $member->appointments();

laravel 5 advance eloquent multiple selection

I have a table containing multiple artist. While creating an event (updating event table) I need to select artists that I want to perform at my event and need to add their ids in the event_artist (transitive) table (that contains event_id & artist_id). How shall I proceed?
You would define a many to many relationship.
In Artist model class:
public function events()
{
$this->belongsToMany(Event::class);
}
In Event model class:
public function artists()
{
$this->belongsToMany(Artist::class);
}
This assumes your pivot table is named artist_event (the other two table names combined in alphabetical order). Otherwise you can pass the pivot table name as the second argument to belongsToMany: belongsToMany(Event::class, 'event_artist').
Then you can attach an artist to an event using $event->artists()->attach($artist);. Or detach $event->artists()->detach($artist);. You can also sync a collection of artists: $event->artists()->sync($artists);. You can also attach, detach or sync events to artists. All three methods will accept either Eloquent models or ids.

How do I define relation between users and points in Eloquent ORM

I have 3 tables:
Users - for storing users
User_point - for associacion between users and points(has only user_id and point_id)
Points for description of points(id, amount, description)
How do I define a relation between these? I tried
public function points(){
return $this->belongsToMany('\App\Point', 'user_point');
}
but when I do
return $user->points()->sum('amount');
it returns just one
Edit:
At first I tried making it like this as it makes more sense:
public function points(){
return $this->hasMany('\App\Point');
}
But it wouldn't work
SUM is an aggregate function and so it should only return one row.
$user->points will be a collection of points attached to that user.
$user->points() is a query that you can do additional work against (i.e. $user->points()->whereSomething(true)->get()).
As user ceejayoz pointed out, using user->points() is going to return a builder which you can do additional work on. I believe using sum() on that will look at the first row returned which is what you indicated is actually happening.
Likely, what you really want to do is $user->points->sum('amount');
That will get the sum of that column for the entire collection.

Extbase Mapping with non-TYPO3-table

I have too classes and two non-TYPO3-tables. I defined a non-TYPO3-table as a table without uid, pid, etc. columns.
My two classes:
class Tx_Abc_Domain_Model_Location extends Tx_Extbase_DomainObject_AbstractEntity
class Tx_Abc_Domain_Model_Facility extends Tx_Extbase_DomainObject_AbstractEntity
My two tables (with columns):
locations
zipcode
city
facility_id
facilities
facility_id
name
I've mapped the attributes like this:
config.tx_extbase.persistence.classes {
Tx_Abc_Domain_Model_Location.mapping {
tableName = locations
columns {
zipcode.mapOnProperty = zipcode
city.mapOnProperty = city
facility_id.mapOnProperty = facility
}
}
Tx_Abc_Domain_Model_Facility.mapping {
tableName = facilities
columns {
facility_id.mapOnProperty = uid
name.mapOnProperty = name
}
}
}
My problem:
The facility attribute of my location model got the type Tx_Abc_Domain_Model_Facility and when I'm looking for a location via the LocationRepository it builds me a location model which contains a facility model.
The problem appears, when I the search I am doing returns several results. i.e. the location with the zipcode 12345 has two different facilities (and the table locations got two rows with different facility_ids), then I would expect to get two location models and each of it got the right facility model.
But instead I get the two location models, which have all same facility model inside. They've got all the facility of the first found location.
Even if I change the type of the facility attribute to integer, there are the wrong ids. But if I enable raw query result in repository I get the correct ids.
I get also the correct ids or models, when I add to both tables an uid-column.
Is there no possibility to map tables without uid column with Extbase models?
Thanks.
Okay, the answer to my last question is: Yes, there is no possibility to map tables without uid column with Extbase models.
There is an existing ticket on forge: http://forge.typo3.org/issues/25984
The reason seems to be the hardcoded $row['uid'] in mapSingleRow() method in Tx_Extbase_Persistence_Mapper_DataMapper class.
If it's not alot of tables you have to map, a work-around could be to create views for those tables to just map the uid.
I.e.:
CREATE VIEW tx_abc_domain_model_facility AS
SELECT facility_id AS uid, facilities.* FROM facilities;

Resources