$post->country relation
yakoffka opened this issue · comments
Hello. Thank you for a wonderful and necessary package.
But I can't figure out how to get the $post->country relation:
Consider this example from the Laravel documentation with an additional level:
Country → has many → User → has many → Post → has many → Comment
class Post extends Model
{
public function country()
{
return $this->hasOneDeepFromReverse((new User())->country());
}
}
return error:
Expected parameter of type '\Staudenmeir\EloquentHasManyDeep\HasManyDeep', '\Illuminate\Database\Eloquent\Relations\BelongsTo' provided
Can you please tell me how to describe this relationship?
Hi @yakoffka,
Please provide the whole exception with its stacktrace. How are you using the relationship when you get this error?
Strictly speaking, I have a slightly different relations:
User{id} → has many → ChatGroup{uuid, user_id} → has many → Chat{uuid, chat_group_uuid} → has many → Post{uuid, chat_uuid}
I was able to describe all connections except $chat->user(). The error occurs in tinker:
TypeError: App\Models\Chats\Chat::hasOneDeepFromReverse(): Argument #1 ($relation) must be of type Staudenmeir\EloquentHasManyDeep\HasManyDeep, Illuminate\Database\Eloquent\Relations\BelongsTo given, called in /var/www/app/Models/Chats/Chat.php on line 137
on 137 line return $this->hasOneDeepFromReverse((new ChatGroup())->user());
(new ChatGroup())->user() return BelongsTo
But, as far as I understand, the receipt scheme is similar. How to get the relation in your example for $post->country()?
Is the example that I described in the first post working?
- I don't know how to get stacktrace in tinker
App\Models\Chats\Chat::hasOneDeepFromReverse(): Argument #1 ($relation) must be of type Staudenmeir\EloquentHasManyDeep\HasManyDeep, Illuminate\Database\Eloquent\Relations\BelongsTo given, called in /var/www/app/Models/Chats/Chat.php on line 137 {"exception":"[object] (TypeError(code: 0): App\Models\Chats\Chat::hasOneDeepFromReverse(): Argument #1 ($relation) must be of type Staudenmeir\EloquentHasManyDeep\HasManyDeep, Illuminate\Database\Eloquent\Relations\BelongsTo given, called in /var/www/app/Models/Chats/Chat.php on line 137 at /var/www/vendor/staudenmeir/eloquent-has-many-deep/src/Eloquent/Traits/ReversesRelationships.php:29)
[stacktrace]
#0 /var/www/app/Models/Chats/Chat.php(137): App\Models\Chats\Chat->hasOneDeepFromReverse(Object(Illuminate\Database\Eloquent\Relations\BelongsTo))
#1 /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(576): App\Models\Chats\Chat->user()
#2 /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(528): Illuminate\Database\Eloquent\Model->getRelationshipFromMethod('user')
#3 /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php(453): Illuminate\Database\Eloquent\Model->getRelationValue('user')
#4 /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php(2218): Illuminate\Database\Eloquent\Model->getAttribute('user')
#5 /var/www/vendor/psy/psysh/src/ExecutionLoopClosure.php(55) : eval()'d code(3): Illuminate\Database\Eloquent\Model->__get('user')
#6 /var/www/vendor/psy/psysh/src/ExecutionLoopClosure.php(55): eval()
#7 /var/www/vendor/psy/psysh/src/ExecutionClosure.php(89): Psy\{closure}()
#8 /var/www/vendor/psy/psysh/src/Shell.php(383): Psy\ExecutionClosure->execute()
#9 /var/www/vendor/psy/psysh/src/Shell.php(354): Psy\Shell->doInteractiveRun()
#10 /var/www/vendor/symfony/console/Application.php(171): Psy\Shell->doRun(Object(Symfony\Component\Console\Input\ArrayInput), Object(Psy\Output\ShellOutput))
#11 /var/www/vendor/psy/psysh/src/Shell.php(329): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArrayInput), Object(Psy\Output\ShellOutput))
#12 /var/www/vendor/laravel/tinker/src/Console/TinkerCommand.php(81): Psy\Shell->run()
#13 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Laravel\Tinker\Console\TinkerCommand->handle()
#14 /var/www/vendor/laravel/framework/src/Illuminate/Container/Util.php(41): Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
#15 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(93): Illuminate\Container\Util::unwrapIfClosure(Object(Closure))
#16 /var/www/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(37): Illuminate\Container\BoundMethod::callBoundMethod(Object(Illuminate\Foundation\Application), Array, Object(Closure))
#17 /var/www/vendor/laravel/framework/src/Illuminate/Container/Container.php(651): Illuminate\Container\BoundMethod::call(Object(Illuminate\Foundation\Application), Array, Array, NULL)
#18 /var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(178): Illuminate\Container\Container->call(Array)
#19 /var/www/vendor/symfony/console/Command/Command.php(308): Illuminate\Console\Command->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#20 /var/www/vendor/laravel/framework/src/Illuminate/Console/Command.php(148): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Illuminate\Console\OutputStyle))
#21 /var/www/vendor/symfony/console/Application.php(1014): Illuminate\Console\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 /var/www/vendor/symfony/console/Application.php(301): Symfony\Component\Console\Application->doRunCommand(Object(Laravel\Tinker\Console\TinkerCommand), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 /var/www/vendor/symfony/console/Application.php(171): Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#24 /var/www/vendor/laravel/framework/src/Illuminate/Console/Application.php(102): Symfony\Component\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#25 /var/www/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(155): Illuminate\Console\Application->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#26 /var/www/artisan(37): Illuminate\Foundation\Console\Kernel->handle(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#27 {main}
"}
/var/www/app/Models/Chats/Chat.php on line 137
What exactly does this line look like? It sounds like you defined a (incorrect) return type ...(): BelongsTo
.
BelongsTo defined in ChatGroup model:
class ChatGroup extends Model
{
...
/**
* @return HasManyDeep
* см. https://github.com/staudenmeir/eloquent-has-many-deep
*/
public function posts(): HasManyDeep
{
return $this->hasManyDeep(Post::class, [Chat::class]);
}
/**
* @return BelongsTo
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
...
}
And here is the code from the model Chat:
class Chat extends Model
{
...
/**
* @return BelongsTo
*/
public function group(): BelongsTo
{
return $this->belongsTo(
ChatGroup::class,
'chat_group_uuid',
'uuid'
);
}
/**
* @return HasMany
*/
public function posts(): HasMany
{
return $this->hasMany(
Post::class,
'chat_uuid',
'uuid'
);
}
/**
* User → has many → ChatGroup → has many → Chat → has many → Post
*/
public function user()
{
return $this->hasOneDeepFromReverse((new ChatGroup())->user()); // line 137
}
...
}
in the User model, the inverse relationship is defined
class User extends Model
{
...
/**
* @return HasMany
*/
public function chatGroups(): HasMany
{
return $this->hasMany(
ChatGroup::class,
'user_id',
'id',
);
}
...
}
Argument #1 ($chatGroup->user()) for $chat->hasOneDeepFromReverse() and truth has a type BelongsTo, but it must be of this type, since this is the inverse relation of HasMany ($user->chatGroup())
I would just like to see a working example of getting a relation $post->country for your example (Country → has many → User → has many → Post → has many → Comment).
class Post extends Model
{
public function country()
{
return $this->hasOneDeepFromReverse((new User())->country());
}
}
If you get this connection without any problems, then the error is hiding somewhere in my code.
I think I figured it out: in this case, you need to use the BelongsToThrough relation
Indeed the BelongsToThrough relation helped. I suffered a little with the indication of custom keys, but it all worked.
class Chat extends Model
{
/**
* Пользователь, которому принадлежит группа данного чата (Chat -> User)
*
* User{id} → has many → ChatGroup{uuid, user_id}
* → has many → Chat{uuid, chat_group_uuid}
* → has many → Post{uuid, chat_uuid}t
*/
public function user(): BelongsToThrough
{
return $this->belongsToThrough(
User::class,
ChatGroup::class,
'chat_group_uuid', // локальный ключ в таблице chats
null,
[
ChatGroup::class => 'chat_group_uuid', // внешний ключ в таблице chats
User::class => 'user_id', // внешний ключ в таблице chat_groups
]
);
}
}
Thanks again for the package!