Yii2: ActiveRecord unlink() could be with the same feature as link ($extraColumns)

Created on 5 Aug 2017  路  8Comments  路  Source: yiisoft/yii2

Hi,
Is there a reason, why unlink in 'BaseActiveRecord' class is without $extraColumns option?
Right now it is possible to save extra info with link, but during unlink, it deletes all records disregarding info in ExtraColumns.

What steps will reproduce the problem?

I have many2many relation table with columns: id (PK) | meeting_id | customer_id | customer_role
A customer may have different roles: initiator, participant, lector etc. (1, 2, 3 etc)
So, during linking, I can fill table with proper values eg:
1st person:
... | 307 | 45 | 1 - initiates meeting
... | 307 | 45 | 2 - participated on meeting as quest
... | 307 | 45 | 3 - participated on meeting as lector
2ndt person:
... | 307 | 46 | 2 - participated on meeting as quest
... | 307 | 46 | 3 - participated on meeting as lector
etc
But if I would like to delete customer nr 45 from lector list using unlink of 'BaseActiveRecord' class, it deletes all records, where meeting_id = 307 and customer_id = 45.

Additional info

I checked the doc of 'link' and 'unlink'. 'Unlink' is missing part of $extraColumns, what 'link' has.
I added $extraColumns to unlink:

public function unlink($name, $model, $delete = false, $extraColumns = [])
{ ...

and in the code added:

foreach ($extraColumns as $k => $v) {
                $columns[$k] = $v;
            }

now it works as I would like it to work.

| Q | A
| ---------------- | ---
| Yii version | 2.0.12

enhancement

All 8 comments

Makes sense but since there's a signature change, it could be adjusted in Yii 2.1 only.

Is there a reason, why unlink in 'BaseActiveRecord' class is without $extraColumns option?

extra columns are used to store extra information for a relation. A relation between two records should have only one entry in the table, not multiple entries with different extra column data. The reference to related tables should be a primary key.

@cebe well, under normal conditions - yes. But in my case scenario, one person can be connected to event as different type (lector, participant, secretary, etc). So in Many2Many relation table (using via method), I relate Event with Person via Participant table (M2M relation table). Participant Model is based on Samdark Cookbook ideas: "Single table inheritance", so there is different types of participants. And the only way to understand the type of participation is by using additional column 'type'.

Therefore it is very useful Extracolumn during link method (as I link event with person and marking participation type), but I am not able to delete only certain type of participation without additional query for finding id in related table (where I still have to use Event+Person+ParticipationType). With existing unlink() all participation's of person/event will be deleted, disregarding type of participation.

Maybe it is only matter of my case scenario. But anyway, thanks for nice framework.

Yes, that's very specific scenario indeed...

BTW, another places we are using similar structure:

  1. sending emails from our CMS
  2. attaching files to emails.

1). A mail receiver can be in list of TO / CC / BCC. So when (after saving draft) I would like to delete somebody from BCC (for example), he is also gone from TO and/or CC (with existing unlink() ).
We found, that using one table with 'relation type' is better choice, than using many tables with similar structure or one table with another table holding that 'type' information. Searching and/or adding new types is much easier within one table.

2). We have to send with email public and private files. We found, there is no reason for duplicating methods in 'AttachmentsPublic' model and 'AttachmentsPrivate' model. Rather than using the same logic (Samdark STI) and having only one model/table/ParentClass with child classes.

As a conclusion, we use $extraColumns (in link() and our modified unlink() ) in those cases, where we have to use M2M relation and reference to STI classes.

Yes, use case is understood and isn't very common. I think the best way to solve it is to issue two delete() statements in transaction wrapping it into your own method.

you can of course create such relations but they are out of the scope that is supported by link() and unlink(). If you have that scenario, you have to write your own code for creating and removing relations.

OK, thank you!

Was this page helpful?
0 / 5 - 0 ratings