Quick ORM
Search…
belongsToMany

Usage

A belongsToMany relationship is a many-to-many relationship. For instance, a User may have multiple Permissions while a Permission can belong to multiple Users.
1
// User.cfc
2
component extends="quick.models.BaseEntity" accessors="true" {
3
4
function permissions() {
5
return belongsToMany( "Permission" );
6
}
7
8
}
Copied!
1
// Permission.cfc
2
component extends="quick.models.BaseEntity" accessors="true" {
3
4
function users() {
5
return belongsToMany( "User" );
6
}
7
8
}
Copied!
The first value passed to belongsToMany is a WireBox mapping to the related entity.
belongsToMany makes some assumptions about your table structure. To support a many-to-many relationship, you need a pivot table. This is, at its simplest, a table with each of the foreign keys as columns.
1
permissions_users
2
- permissionId
3
- userId
Copied!
As you can see, Quick uses a convention of combining the entity table names in alphabetical order with an underscore (_) to create the new pivot table name. If you want to override this convention, you can do so by passing the desired table name as the second parameter or the table parameter.
1
// User.cfc
2
component extends="quick.models.BaseEntity" accessors="true" {
3
4
function permissions() {
5
return belongsToMany( "Permission", "user_permission_map" );
6
}
7
8
}
Copied!
Quick determines the foreign key of the relationship based on the entity name and key values. In this case, the User entity is assumed to have a userId foreign key and the Permission entity a permissionId foreign key. You can override this by passing a foreignKey in as the third argument and a relatedKey as the fourth argument:
1
return belongsToMany(
2
"Permission",
3
"user_permission_map",
4
"FK_UserId",
5
"FK_PermissionID"
6
);
Copied!
Finally, if you are not joining on the primary keys of the current entity or the related entity, you can specify those keys using the last two parameters:
1
return belongsToMany(
2
"Permission",
3
"user_permission_map",
4
"FK_UserId",
5
"FK_PermissionID",
6
"user_id",
7
"permission_id"
8
);
Copied!
The inverse of belongsToMany is also belongsToMany. The foreignKey and relatedKey arguments are swapped on the inverse side of the relationship.
1
// Permission.cfc
2
component extends="quick.models.BaseEntity" accessors="true" {
3
4
function user() {
5
belongsToMany( "User", "user_permission_map", "FK_PermissionID", "FK_UserId" );
6
}
7
8
}
Copied!
If you find yourself needing to interact with the pivot table (permissions_users) in the example above, you can create an intermediate entity, like UserPermission. You will still be able to access the end of the relationship chain using the hasManyThrough relationship type.
1
// User.cfc
2
component extends="quick.models.BaseEntity" accessors="true" {
3
4
function userPermissions() {
5
return hasMany( "UserPermission" );
6
}
7
8
function permissions() {
9
return hasManyThrough( [ "UserPermissions", "Permission" ] );
10
}
11
12
}
Copied!

attach

Use the attach method to relate two belongsToMany entities together. attach can take a single id, a single entity, or an array of ids or entities (even mixed and matched) to associate.
1
var post = getInstance( "Post" ).findOrFail( 1 );
2
var tag = getInstance( "Tag" ).create( { "name": "miscellaneous" });
3
4
// pass an id
5
post.tags().attach( tag.getId() );
6
// or pass an entity
7
post.tags().attach( tag );
Copied!

detach

Use the detach method to remove an existing entity from a belongsToMany relationship. detatch can also take a single id, a single entity, or an array of ids or entities (even mixed and matched) to remove.
1
var post = getInstance( "Post" ).findOrFail( 1 );
2
var tag = getInstance("Tag").firstWhere( "name", "miscellaneous" );
3
4
// pass an id
5
post.tags().detach( tag.getId() );
6
// or pass an entity
7
post.tags().detach( tag );
Copied!

sync

Sometimes you just want the related entities to be a list you give it. For these situations, use the sync method.
1
var post = getInstance( "Post" ).findOrFail( 1 );
2
3
post.tags().sync( [ 2, 3, 6 ] );
Copied!
Now, no matter what relationships existed before, this Post will only have three tags associated with it.

Relationship Setter

You can also influence the associated entities by calling "set" & relationshipName and passing in an entity or key value.
1
var someTag = getInstance( "Tag" ).findOrFail( 2 );
2
var post = getInstance( "Post" ).first();
3
post.setTags( [ 4, 12, someTag );
Copied!
This code calls sync on the relationship. After executing this code, the post would be updated in the database to be associated with the tags passed in (4, 12, and 2). Any tags that were previously associated with this post would no longer be and only the tags passed in would be associated now.

Signature

Name
Type
Required
Default
Description
relationName
string
true
The WireBox mapping for the related entity.
table
String
false
Table names in alphabetical order separated by an underscore.
The table name used as the pivot table for the relationship. A pivot table is a table that stores, at a minimum, the primary key values of each side of the relationship as foreign keys.
foreignPivotKey
String | [String]
false
keyNames()
The name of the column on the pivot table that holds the value of the parentKey of the parent entity.
relatedPivotKey
String | [String]
false
The name of the column on the pivot table that holds the value of the relatedKey of the ralated entity.
parentKey
String | [String]
false
The name of the column on the parent entity that is stored in the foreignPivotKey column on table.
relatedKey
String | [String]
false
The name of the column on the related entity that is stored in the relatedPivotKey column on table.
relationMethodName
String
false
The method name called on the entity to produce this relationship.
The method name called to retrieve this relationship. Uses a stack backtrace to determine by default.
<b></b>
DO NOT PASS A VALUE HERE UNLESS YOU KNOW WHAT YOU ARE DOING.
Returns a BelongsToMany relationship between this entity and the entity defined by relationName.

Visualizer