Imagine following DB tables:
Clients Users
| Id | name | user_id | | ID | name |
| -- | ----- | ------ | | -- | ------ |
| 1 | NULL | 1 | | 1 | David |
| 2 | Peter | NULL |
Not each client is automatically user, but user may have client account. Users table contains only registered users, if user is client (dont have to be) the client account is created.
I have succcessfully made relations between these table is Laravel. Eloquent querying woks fine, eg.:
clients.php
public function userAcc() {
return $this->hasOne('User', 'id', 'user_id');
}
user.php
public function clientAcc() {
return $this->hasOne('Clients', 'user_id', 'id');
}
The problem is that when i query these tables:
Clients::with('userAcc')->get()
In view i have to make lots of ifs, like:
#if($client->userAcc)
{!! $client->userAcc->name !!}
#else
{!! $client->name !!}
#endif
Is there any workaround in laravel that allows me to format collections on each select query? Something like Accessor but on whole collection, so i will be able to do something like this in view:
{!! $client->realname !!}
And it writes client name from particular table.
Many thanks for any suggestions
This is the Laravel way to accomplish this:
class Client extends Model {
public $appends = ['realname'];
public function userAcc() {
return $this->hasOne('User', 'id', 'user_id');
}
public function getRealnameAttribute(){
return $this->userAcc? $this->userAcc->name : $this->name;
}
Now it will be accessible through $client->realname and it will be included in $client->toJson() and $client->toArray()
You can make a method for that:
public function getName()
{
return $this->userAcc?$this->userAcc->name:$this->name;
}
In your blade just call the function:
{{$client->getName()}}
Related
I'm quite new in Lumen but I have to do this because i have final task about Laravel.
So, i do have these two tables, the users and userTypes table.
usertypes table
+-----------------------+
| userTypeId | typeName |
+-----------------------+
| 1 | admin |
| 2 | buyer |
| 3 | store |
+-----------------------+
users table
+----------------------------------+
| id | name | email | userTypeId |
+----------------------------------+
| 1 | john | e#e.com | 2 |
+----------------------------------+
Now, what i was hoping the output for is something like this:
{
"data" : {
"id" : 1,
"nama" : "john",
"email" : "e#e.com",
"usertypes" : {
"typesName" : "buyer"
}
}
}
I've tried hasMany() and hasOne() and more but the "userTypes" field still return []. Here's the model for both of that.
User.php
....
public function usertype() {
return $this->hasMany(UserTypes::class, 'userTypeId');
}
....
UserTypes.php
.....
public function User() {
return $this->belongsTo(User::class);
}
.....
And here's the UserController.php
...
public function user($id) {
$user = User::with(['usertype'])->findOrFail($id);
return response()->json(['data' => $user]);
}
...
Any way to fix this? I appreciated for anyone who willing to help me. Thank you 🙏🙏
Its better to use find method you use route model binding. when you pass id
to method User $user auto find user from databse. now we have $user so we
call relation $user->usertype.
public function user(User $user) {
return response()->json(['data' => $user->usertype]);
}
So it appears that i'm not fully understand the meaning of the "third parameters" and thanks to someone in telegram group that helping me out, in the User model it should be:
return $this->hasOne(UserTypes::class, 'userTypeId', 'userTypeId');
and it works. Second parameter is the foreign key on the users table, third parameter is the primary column name in that userTypes table. Hope it clears the dumb newbie like me.
I am testing out Lumen here and have a question regarding many-to-many relationship.
I've read the documentation, but I've either overlooked the answer or I might be dumber then I think. Also have to add that I am pretty new to the MVC pattern.
So I have an example here where we can have many permissions, many users and each user can have many permissions.
I have 3 database tables:
-------------------------------------
| users | id | firstname | lastname |
-------------------------------------
----------------------------------------------------------------
| permissions_users | id | permission_id | user_id | from | to |
----------------------------------------------------------------
----------------------------------
| permissions | id | name | desc |
----------------------------------
And for now I've created 2 models:
User:
public function permissions(){
return $this->belongsToMany('App\Permission', 'permissions_users', 'user_id', 'permission_id');
}
Permission:
public function users(){
return $this->belongsToMany('App\User', 'permissions_users', 'permission_id', 'user_id');
}
Now my question is, what if I want to fetch the "from" and "to" dates in the permissions_users table, what do I do?
Do I create a model called PermissionUser "between" that act as a middleman between User and Permission or is there another way?
Thanks
You can define these attributes also in select on relation. I think this will work for you.
public function permissions()
{
return $this->belongsToMany('App\Permission', 'permissions_users', 'user_id', 'permission_id')->select(['from', 'to']);
}
You might need to add permission columns too in select else it might show only from and to in your relation object.
public function permissions()
{
return $this
->belongsToMany('App\Permission', 'permissions_users', 'user_id', 'permission_id')
->withPivot('from', 'to');
}
foreach($user->permissions as $permission){
$permission->pivot->from;
$permission->pivot->to;
}
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'm trying to obtain a three level relationship data, but I'm lost about it using laravel 5.1
I'll try to explain my scenario, hope you can help me.
I've got two models called Host and User.
This models are grouped by Hostgroup and Usergroup models, using a Many To Many relationship.
Then I've got a table called usergroup_hostgroup_permissions which relation an Usergroup with a Hostgroup:
+--------------+----------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+----------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| usergroup_id | int(10) unsigned | NO | MUL | NULL | |
| hostgroup_id | int(10) unsigned | NO | MUL | NULL | |
| action | enum('allow','deny') | NO | | allow | |
| enabled | tinyint(1) | NO | | 1 | |
+--------------+----------------------+------+-----+---------------------+----------------+
I'd like to obtain a list of users that belongs to an usergroup with a relation in this table with a hostgroup where my host belongs to.
For example:
My host_1 belongs to DEV_servers.
On usergroup_hostgroup_permissions table, there's an entry that allows developers to access to DEV_servers.
The usergroup developer has 3 users user_1, user_2 and user_3.
Any hint? Thanks in advance!
In order to obtain a list of users in a particular host, you need to nest all the underlying relationships (via .) using a whereHas method on the User model. i.e.
$users = User::whereHas('usergroup.hostgroups.hosts', function($q) use ($hostID){
$q->where('id', $hostID);
})->get();
Moreover, if you want to check against whether the user is allowed to access that particular host, then you may chain another where() to the above as such:
$users = User::whereHas('usergroup.hostgroups.hosts', function($q) use ($hostID){
$q->where('id', $hostID)->where('usergroup_hostgroup_permissions.action', 'allow');
})->get();
Note: If you are warned on an ambiguous id field, try including the table hosts to which the id belongs to as well, i.e. hosts.id.
I am assuming that you have defined the relations for those models as follows:
class HostGroup extends Eloquent {
/** ...
*/
public function hosts(){
return $this->hasMany('App\Host');
}
public function usergroups(){
return $this->belongsToMany('App\UserGroup', 'usergroup_hostgroup_permissions');
}
}
class Host extends Eloquent {
/** ...
*/
public function hostgroup() {
return $this->belongsTo('App\HostGroup');
}
}
class UserGroup extends Eloquent {
/** ...
*/
public function users(){
return $this->hasMany('App\User');
}
public function hostgroups(){
return $this->belongsToMany('App\HostGroup', 'usergroup_hostgroup_permissions');
}
}
class User extends Eloquent {
/** ...
*/
public function usergroup(){
return $this->belongsTo('App\UserGroup');
}
}
Hope it turns out to be helpful.
I'm trying to order the tests for each user in descending order of created_at. I tried it in the template but I didn't succeed. These are my tables:
| users | | courses | | tests |
| ---------- | |------------| |------------|
| id | | id | | id |
| name | | name | | name |
| created_at | | created_at | | created_at |
| user_id | | course_id |
A user has many courses and a course has many tests. I'll like to order all the tests in descending order of created_at.
I tried this in my template:
#foreach(User::find($user->id)->courses as $course)
#foreach(Course::find($course->id)->tests as $test)
<p>Name: {{$test->name}}</p>
<p>Date: {{$test->created_at}}</p>
#endforeach
#endforeach
Edit: There are my models
User.php
public function courses()
{
return $this->hasMany('Course');
}
Course.php
public function user()
{
return $this->belongsTo('User');
}
public function test()
{
return $this->hasMany('Test');
}
Test.php
public function courses()
{
return $this->belongsTo('Course');
}
You may try this, do it in your Controller:
$users = User::with(array('courses.tests' => function($query) {
$query->orderBy('tests.created_at', 'desc');
}))->find($user->id);
Then load the view and pass the $user object like this:
return View::make('your_view_name')->withuser($user);
Then in your view try something like this:
#foreach($user->courses->tests as $test)
<p>Name: {{ $test->name }}</p>
<p>Date: {{ $test->created_at }}</p>
#endforeach
You could simply add the orderBy command to your query, like:
#foreach($user->courses as $course)
#foreach($course->tests()->orderBy('created_at', DESC)->get() as $test)
<p>Name: {{$test->name}}</p>
<p>Date: {{$test->created_at}}</p>
#endforeach
#endforeach
Look that it's not a good practice to make queries in the views, so I changed your query in some variables you should be setting in your controller.
Also change test() method to tests(), because it's a one-to-many relation, and it's clearer to have plurals as method name.