Here is my model User.php
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password', 'cell_phone', 'province_id', 'city_id', 'job'
];
protected $hidden = [
'password', 'remember_token',
];
public function city()
{
return $this->belongsTo('City');
}
}
And here is a part of my controller:
$user_info = User::find(Auth::user()->id);
dd($user_info->city);
And it throws this:
"Undefined class constant 'city'"
How can I fix the problem?
Tables structure:
// users
+----+--------+---------+----------
| id | name | city_id | ...
+----+--------+---------+----------
| 1 | Jack | 5 | ...
// city
+----+--------+
| id | name |
+----+--------+
| 1 | Tehran |
You need to pass full class name:
return $this->belongsTo('App\City');
Or:
return $this->belongsTo(City::class);
Also, you don't need to do that:
$user_info = User::find(Auth::user()->id);
Because Auth::user() already has user instance loaded, you can just get city instance with:
Auth::user()->city
Basically , you don't provide full path of your class name of city that's why you belongs To relation not working properly.
for example your code must be
return $this->belongs To('App/City');
Because your in app folder you have city class module and others.
Related
I have a Person class (App\Models\Person) and an Organization class (App\Models\Organization) which have a polymorphic relationship with User (App\Models\User). I am using Modules (nwidart/laravel-modules).
In my App\Providers\AppServiceProvider in the boot method I have this relationship:
Relation::morphMap(
[
'organizations' => 'App\Models\Organization',
'persons' => 'App\Models\Person',
]
);
Now, I have a module called Contracts, that module has a Person model (Modules\Contracts\Entities\Person) which extends from App\Models\Person. I also have a User model (Modules\Contracts\Entities\User) which extends from App\Models\User.
I added the following code to the ContractsServiceProvider boot method:
Relation::morphMap(
[
'persons' => 'Modules\Contracts\Entities\Person',
]
);
Now, if I go to any controller and I load a Person like this:
$person = \App\Models\Person::find( 1 );
The relationship with User doesn't exist, so I can't do $person->users()->first();
But if I load a Person like this:
$person = \Modules\Contracts\Entities\Person::find( 1 );
The relationship works like a charm.
The fun part is that all the relationship methods with users are inside the files User.php and Person.php in the app\Models directory.
In app\Models\User.php I have:
class User extends Authenticatable implements MustVerifyEmail {
public function usable()
{
return $this->morphTo();
}
}
In my app\Models\Person.php
class Person extends Model {
public function users()
{
return $this->morphMany( User::class, 'usable', 'usable_type', 'usable_id' );
}
}
Also, when I create an \App\Models\Userfrom an \App\Models\Person like this:
$person = \App\Models\Person::find( 1 );
$person->users()->create( [ ... ] );
The record in the database in the users table is like this:
+------------------------------------------------------------------------+
| id | email | usable_id | usable_type |
+------------------------------------------------------------------------+
| 1 | some#email.com | 3 | App\Models\Person |
+------------------------------------------------------------------------+
But if I create the user from a \Modules\Contracts\Entities\Person like this:
$person = \Modules\Contracts\Entities\Person::find( 1 );
$person->users()->create( [ ... ] );
The record in the database in the users table is like this:
+------------------------------------------------------------------------+
| id | email | usable_id | usable_type |
+------------------------------------------------------------------------+
| 1 | some#email.com | 3 | persons |
+------------------------------------------------------------------------+
I wonder if the ContractsServiceProvider is somehow overriding the AppServiceProvider and causing my relationship to fail. Any help would be appreciated.
Thanks
I have tables as follows where role_id is the foreign key of the roles table and user_id and setter_id are the foreign key of the users table.
table 1:
+---------------------+
| users |
+---------------------+
| id |
| name |
| email |
| password |
+---------------------+
table 2:
+---------------------+
| roles |
+---------------------+
| id |
| name |
+---------------------+
pivot table:
+---------------------+
| role_user |
+---------------------+
| role_id |
| user_id |
| setter_id |
+---------------------+
The models I have defined:
User Model:
class User extends Model
{
public $timestamps = false;
public function roles()
{
return $this->belongsToMany(Role::class);
}
}
Role Model:
class Role extends Model
{
public $timestamps = false;
public function users()
{
return $this->belongsToMany(User::class);
}
}
How do I change my models so that I can get the data as shown below?
user -> roles -> setter : The user and its roles and the setter of each role for user
Thank you...
You will never be able to access the setter by calling it in the roles collection.
This is wrong:
$user->roles->setter
Let's see an example that will work:
foreach($user->roles as $role)
{
dd($role->pivot->setter)
}
To be able to do that, you need to change your models to reflect something like this:
User
class User extends Model
{
public $timestamps = false;
public function roles()
{
return $this->belongsToMany(Role::class)
->using(UserRolePivot::class)
->withPivot([
'role_id',
'user_id',
'setter_id',
]);
}
}
Role
class Role extends Model
{
public $timestamps = false;
public function users()
{
return $this->belongsToMany(User::class)
->using(UserRolePivot::class)
->withPivot([
'role_id',
'user_id',
'setter_id',
]);
}
}
Pivot
use Illuminate\Database\Eloquent\Relations\Pivot;
class UserRolePivot extends Pivot
{
protected $fillable = [
'role_id',
'user_id',
'setter_id',
];
public function role()
{
return $this->belongsTo(Role::class , 'role_id');
}
public function user()
{
return $this->belongsTo(User::class , 'user_id');
}
public function setter()
{
return $this->belongsTo(User::class , 'setter_id);
}
}
You can either update the belongsToMany calls to include the setter_id on the pivot aswell, and then access it via ->pivot->setter_id and retrieve a model using that id.
return $this->belongsToMany(Role::class)->withPivot('setter_id');
Or (and what I would personally go for) you could define a custom pivot model, and create a setter() relationship there, so you could retrieve the model directly from the pivot.
My User model is like this :
class User extends Authenticatable
{
protected $primaryKey = 'user_id';
protected $fillable = [
'username',
'password',
'name',
'family',
'supervisor'
];
public function children()
{
return $this->hasMany(\App\User::class, 'supervisor', 'user_id')->with('children');
}
}
As you can see there a supervisor column that specify parent of a user.
Now to fetch all children of user models that have supervisor= null, I wrote this :
return User::with('children')->whereNull('supervisor')->get();
but it return this error always :
PHP Warning: Illegal offset type in D:\wamp\www\zarsam-app\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Relations\HasOneOrMany.php on line 168
Table users have these data :
+---------+-------------+---------+--------------+------------+
| user_id | username | name | family | supervisor |
+---------+-------------+---------+--------------+------------+
| 1 | 09139616246 | ahmad | badpey | null |
| 7 | alinasiri | ali | nasiri arani | 1 |
| 8 | zahedi | mostafa | zahedi | 1 |
| 9 | hsan | hasan | ghanati | 8 |
+---------+-------------+---------+--------------+------------+
Update :
I found that problem is that I have a accessor same name supervisor attribute like this :
public function getSupervisorAttribute($value)
{
return is_null($value) ? null : User::select('user_id', 'name', 'family')->find($value);
}
I added that because I want to return supervisor user as an object.
But now in this case, what do I do ?
Try with this setup:
public function children()
{
return $this->hasMany(\App\User::class, 'supervisor', 'user_id');
}
And fetching them like
return User::with('children.children')->whereNull('supervisor')->get();
If this doesn't resolve your issue, then your relationships are not well defined, then I suggest reading about foreignand local keys inside your children.children model
NOTE:
HasOneOrMany.php
...
return $results->mapToDictionary(function ($result) use ($foreign) { //line in question
...
And when I found that method, this is what it said:
/**
* Run a dictionary map over the items.
*
* The callback should return an associative array with a single key/value pair.
*
* #param callable $callback
* #return static
*/
public function mapToDictionary(callable $callback)
I want to point out The callback should return an associative array with a single key/value pair. Which means you cannot do it recursively, at least I believe you can't.
Problem
I created a simple friendship relationship for my Laravel app which all worked ok until I noticed that when I queried the friendship of a user it would only search the current user on the UID1 field.
Since friendships are in essence a two-way relationship, Im trying to find a way in a laravel Model to retrieve ALL friendships relations by multiple columns.
Current Implementation
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'friends', 'uid1');
}
Ideal Implementation
public function friends()
{
$a = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
$b = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid2');
return combine($a,$b);
}
Table Structure
+----------------------+
| users table |
+----------------------+
+----| id: primary UserID |
| | fname: string |
| +----------------------+
|
|
| +----------------------+
| | friends table |
| +----------------------+
| | id: primary iD |
| | |
+----| uid1: user_id |
| | |
+----| uid2: user_id |
+----------------------+
The current implementation will only result in 1 of these records returning if the Current UserID = 1 as per the data in the friends table below.
+-------------------------------+
| friends table (data) |
+--------|---------|------------+
| id | uid1 | uid2 |
+--------|---------|------------+
| 1 | 1 | 7 |
| 2 | 7 | 1 |
| 3 | 9 | 1 |
+-------------------------------+
User Model
<?php
namespace App\Modules\Users\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $table = 'users';
protected $fillable = [
'username', 'email', 'password', .... .
];
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
}
Environment
Server = Homestead/linux
PHP = 7
MySQL
Update
I have a FriendShip helper class I created which does something similar, however in this function I pass in the UserID explicitly
Friendship::where( [
[ 'uid1' ,'=', $uid],
])->orWhere( [
[ 'uid2', '=', $uid]
])->all();
You can add additional conditions when you're declaring relationship by simply chaining it.
<?php
//...
class User extends Model {
//...
public function friends() {
return $this->hasMany(/*...*/)->orWhere('uid2', $this->id);
}
//...
But keep in mind that eloquent is not grouping the first conditions of relation in parenthesis so you might end with SQL that will not work as expected in some cases (if using or, and should be fine)
For example the above might result in a SQL that looks like this
SELECT * FROM users_friends WHERE uid1 = ? AND uid1 IS NOT NULL OR uid2 = ?
Which is a correct SQL statement but without grouping you will not get the result that you're expecting.
Another way is to use accessor and two separate relationships
<?php
//...
public function friends1() {
return $this->belongsToMany(User::class, 'users_friends', 'uid1');
}
public function friends2() {
return $this->belongsToMany(User::class, 'users_friends', 'uid2');
}
public function getFriendsAttribute() {
return $this->friends1->merge($this->friends2);
}
//...
But this way you get two separate trips to DB.
I am trying to only return specific profiles for users that have roles (role_id 5 & 6) that are active in both tables. It would also be nice if I can order by first_name ASC as well (user table).
user
+---------+---------+-------------+-----------+
| user_id | role_id | first_name | is_active |
+---------+---------+-------------+-----------+
| 1 | 5 | Dan | 1 |
| 2 | 6 | Bob | 0 |
+---------+---------+-------------+-----------+
profile
+------------+---------+------+-------------+-----------+
| profile_id | user_id | bio | avatar | is_active |
+------------+---------+------+-------------+-----------+
| 1 | 1 | text | example.jpg | 1 |
| 2 | 2 | text | noimage.gif | 1 |
+------------+---------+------+-------------+-----------+
My user model
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class User extends Model{
protected $table = 'user';
protected $primaryKey = 'user_id';
protected $fillable = [
'role_id',
'first_name',
'is_active'
];
public function scopeActive(){
return $this->where('is_active', '=', 1);
}
public function role(){
return $this->belongsTo('App\Model\Role');
}
public function profile(){
return $this->hasOne('App\Model\Profile');
}
}
My profile model
namespace App\Model;
use Illuminate\Database\Eloquent\Model;
class Profile extends Model{
protected $table = 'profile';
protected $primaryKey = 'profile_id';
protected $fillable = [
'user_id',
'avatar',
'is_active'
];
public function scopeActive(){
return $this->where('is_active', '=', 1);
}
public function user(){
return $this->belongsTo('App\Model\User');
}
}
My UserController
namespace App\Controller\User;
use App\Model\User;
use App\Model\Profile;
use App\Controller\Controller;
final class UserController extends Controller{
public function listExpert($request, $response){
$user = User::active()->whereIn('role_id', array(5, 6))->orderBy('first_name', 'asc')->get();
$profile = $user->profile ?: new Profile;
$data['experts'] = $profile->active()->get();
$this->view->render($response, '/Frontend/experts.twig', $data);
return $response;
}
}
So I am getting all of my records just fine. I am getting all the profiles but not the ones that belong only to role_id's 5 & 6 in the user table. Also if I set is_active to 0 in the user table, they still show. But if I set is_active in the profile table they do not. I need them to not show whether the User or Profile table has those rows set to inactive. Because you can have a user but they may not want an active profile.
Okay I got it!
$data['experts'] = User::whereIn('role_id', array(5, 6))
->where('is_active', '1')
->whereHas('profile', function($q){
$q->where('is_active', '1');
})
->with('profile')
->orderBy('first_name', 'ASC')
->get();
In case you want to know how to return this in twig....
{% if experts|length > 0 %}
<ul>
{% for item in experts %}
<li>First Name: {{ item.first_name }}, Bio: {{ item.profile.bio }}, Avatar: {{ item.profile.avatar }}</li>
{% endfor %}
</ul>
{% else %}
<p>No records found.</p>
{% endif %}