Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inverse relationship #5

Open
Agufi28 opened this issue Feb 8, 2023 · 5 comments
Open

Inverse relationship #5

Agufi28 opened this issue Feb 8, 2023 · 5 comments

Comments

@Agufi28
Copy link

Agufi28 commented Feb 8, 2023

Hi, I was wondering if by any change you could add support for inverse relationships. Same functionality but from the other side of the relartion. Thanks!

@korridor
Copy link
Owner

korridor commented Feb 8, 2023

Hi @Agufi28,

thanks for your issue!
I don't really get your request. The inverse already exists, and it's a normal BelongsTo relation.
It's likely that I'm just misunderstanding your request.
Could you give me a simple real world example for this, maybe I can help you better then.

@Agufi28
Copy link
Author

Agufi28 commented Feb 9, 2023

Hi, thank you for your answer. I'll give you an example:

Model Children:

  • id
  • id_mother
  • id_father

Model Parent:

  • id
  • name

I need to get both parents from within the child model.

It would be something like this:

public function parents(){
    return $this->hasManyMerged(Parent::class, "id", ["id_mother","id_father"]);
}

The currents state of the library lets me do the relation from the Parent class. It's something like:

public function children(){
    return $this->hasManyMerged(Child::class, ["id_mother","id_father"]);
}

This is not the exact escenario where I need the relation because the real one is far too complicated to use as an example. But it's essentially the same. I need to get bot parents from within the child.

Thank you very much!

@korridor
Copy link
Owner

Hi @Agufi28,

Ok, so for the example in the README the Message model would have a relation named something like participants, that returns a query with ->whereIn('id', [$sender, $receiver])?

Maybe something like this:

public function participants(): BelongsToMerged
{
    return $this->belongsToMerged(User::class, ['sender_user_id', 'receiver_user_id']);
}

If this is what you mean, then I think that this is a good addition to this package and I will add it when I find the time in the following weeks (hopefully not months).
If you want it earlier, or you are motivated, I would be open to PR! :)

@aeruggiero
Copy link

aeruggiero commented Sep 13, 2023

Hi @korridor,
first of all great library!

I'm using this thread because I think it's related to my issue:
I have a table users and a table friends.
The table friends has user_id_1 and user_id_2, plus some additional columns, but those first two are the one that relate two users.
With the HasManyMerged for a $user, I can get all the records in the friends table, no matter if the $user->id is the user_id_1 or the user_id_2 (and that's GREAT!).
But I would like to obtain also the other user info, something to use with the "with" relation, for example.
Let's say that

class User{
public function friends(){
return $this->hasManyMerged(Friend::class, ['user_id_1', 'user_id_2']);
}
}

I would like to know how I can get something like
$user->friends()->with('friendDetails'), in order to have a collection of users related to my $user through the friend table so that I can also perform additional queries on the friends like "where" (for example $user->friends()->with('friendDetails')->where('name', 'LIKE', '%something%').
Thanks!

@bmooreitul
Copy link

bmooreitul commented Apr 1, 2024

There is definitely a better way to do this... but my workaround using the existing code was to use the existing package classes and make new ones in the app/traits folder.

<?php

declare(strict_types=1);

namespace App\Traits;

use Illuminate\Database\Eloquent\Model;

trait BelongsManyMergedRelation
{
    /**
     * @param  class-string  $related
     * @param  string[]|null  $foreignKeys
     * @param  string|null  $localKey
     * @return BelongsManyMerged
     */
    public function belongsManyMerged(string $related, ?array $foreignKeys = null, ?string $localKey = null): BelongsManyMerged
    {
        $instance       = new $related();
        $localTable     = self::getTable();
        $actualLocalKey = $localTable.'.'.self::getKeyName();
        $localKey       = $localKey ?: $instance->getKeyName();
        $targetTable    = $instance->getTable();
        

        $foreignKeys = array_map(function ($foreignKey) use ($localTable) {
            return $localTable . '.' . $foreignKey;
        }, $foreignKeys);


        $newQuery = $instance->newQuery()->join($localTable, function($join) use($foreignKeys, $targetTable, $localKey){
            foreach($foreignKeys as $i => $foreignKey) $join->{($i >= 1 ? 'orOn' : 'on')}($targetTable.'.'.$localKey, '=', $foreignKey);             
        })->select($targetTable.'.*');

        return new belongsManyMerged($newQuery, $this, [$actualLocalKey], $localKey);
    }

    /**
     * Get the primary key for the model.
     *
     * @return string
     */
    abstract public function getKeyName();
}

Then I just added a BelongsManyMerged class in the app/Traits folder that was copy and paste of this package HasManyMerged class, while simply renaming the class and namespace.

<?php

declare(strict_types=1);

namespace App\Traits;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;

/**
 * @template TRelatedModel of Model
 * @extends Relation<TRelatedModel>
 */
class BelongsManyMerged extends Relation
{
...

After doing this I was able to access the method ->belongsManyMerged(ParentClass, [array of local keys], parentLocalKey) exactly as expected including all query builder features.

For anyone else who is looking for a way to use this package for the inverse of a relationship.

Until this feature is added to the package, hopefully this helps someone out with inverse relationships.


Please note, I would've forked this branch and submitted a merge request to this repo, But I know this is just a workaround and there's a better way to do this.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants