I have two tables 1)users
{ id, password }
2)expertise { id, expertise}
the relationship I have is
Models
Expertise.php
function User()
{
$this->hasOne('Expertise');
}
User.php
function Expertise()
{
$this->hasOne('User');
}
So how can I query using Eloquent to get the first 10 users with a certain expertise?
I want to join users.id = expertise.id and get the first 10 people with a specified expertise (Where clause).
Beginner to laravel, I've checked other sources but was not successful
Right now you are having a problem with the way that you modeled your data. If you have a one-to-one relationship the best practice to model it is to have one entity store the id of the other. The Laravel convention for this is to have a column named <model>_id:
Users
| id | password |
Expertises
| id | expertise | user_id |
Then in your models you can do this:
Models
Expertise.php
class Expertise extends Eloquent
{
public function User()
{
// because expertise has a column user_id
// expertise belongs to user
return $this->belongsTo('User');
}
}
User.php
class User extends Eloquent
{
public function Expertise()
{
// because expertise is the one with the column
// user_id, user has one expertise
return $this->hasOne('Expertise');
}
}
The Query
After you have all this set up, to be able to query the first 10 users with a certain expertise you can do this.
$users = User::whereHas('Expertise', function($q)
{
$q->where('expertise', '=', <expertise you are looking for>)
})
->take(10)
->get();
To get a further reading in querying relationships in Laravel please take a look at this:
Laravel - Querying Relationships
Keep in mind
keep in mind that the tables name must be plural, if not then you should specify the name of the table inside the model:
protected $table = 'expertise';
Related
So, I have a legacy Database, with a poorly designed structure that has recently been moved to Laravel, but with some hacky nonsense to get it to work with models. Given the following Tables:
|==========================|====|============|===========|
| companies | id | token | name |
|--------------------------|----|------------|-----------|
| people_{companies.token} | id | first_name | last_name |
|==========================|====|============|===========|
The companies table contains multiple records, with an auto-incrementing ID, unique token, and name.
Each Company has its own people_{companies.token} table, instead of a single people table, with an associated client_id.
At first, this meant I couldn't use a standard Company and Person Model/Relationships, as protected $table needs to be static. We got around this with a DynamicBinding Trait:
<?php
namespace App\Models\Traits;
trait DynamicBinding {
protected $connection = null;
protected $table = null;
public function bind(string $connection, string $table) {
$this->setConnection($connection);
$this->setTable($table);
}
public function newInstance($attributes = [], $exists = false) {
$model = parent::newInstance($attributes, $exists);
$model->setTable($this->table);
return $model;
}
}
This allows for setting a table on the fly:
$company = Company::first();
$people = (new Person())->setTable("people_{$company->token}");
$person = $people->first();
This works perfectly fine, returning the first record from the people_{$company->token} table, and facilitating most functionality required. Now, I'd like to make this work with Relationships. Given the following example:
// Person.php
public function company() {
return $this->belongsTo(Company::class);
}
$company = Company::first();
$people = (new Person())->setTable("people_{$company->token}");
$person = $people->first(); // No Issue
$peopleWithCompany = $people->with('company')->first(); // Cannot find table `people`
This returns the error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'database.people' doesn't exist (SQL: select * from people limit 1)
Essentially, as soon as ->with() (or other functions, like ->query(), etc) is appended, it tries to perform the query based on the determined table (people from Person) instead of the table set via $people->setTable().
Does anyone have any experience connecting models to this kind of data structure, while allowing use of Eager Loading with Relationships? And sidenote, there is a plan to migrate everything to a single people table, but unfortunately not anytime soon...
Thanks in advance!
Part of my application is private messages between 2 users.
I have a converstations table that has user1 and user2 foreign keys.
Now I wanna have an eloquent function in the User model where I can get his conversations. But a user could be user1 or user2 in any given conversation.
This function for example will only account to conversations where I happen to be user1.
public function conversations()
{
return $this->hasMany('App\Conversation', 'user1');
}
So how can I do it?
A suggestion into your approach would be to store the users of a Conversation in a pivot table. So a Conversation can have more than, in your case, two users. This will lead to easier queries and more expension options. In that case you would just have to do the following:
return $this->belongsToMany(Conversation::class);
Check the docs for more info.
Addition to comment
If you really need this table to have those two columns people would normally do the following:
return $this->hasMany(Conversation::class, 'user1')->orWhere('user2', $this->id);
However since this is an orWhere it could get you incorrect records. This query is executed:
select * from "conversations" where "conversations"."user1" = 1 and "conversations"."user1" is not null or "user2" = 1
But there I have found another way. There is a noConstraints method on the Relation abstract class , from which all relation classes extend, that allows you to modify the whole query:
use Illuminate\Database\Eloquent\Relations\HasMany;
return HasMany::noConstraints(function () {
return $this->hasMany(Conversation::class)
->where('user1', $this->id)
->orWhere('user2', $this->id);
});
This will result in the query what you are looking for:
select * from "conversations" where "user1" = 1 or "user2" = 1
I am not sure how this will effect eagerloading and such.
Still I suggest having a pivot table to keep your database/application flexible.
public function conversations()
{
if(test_for_user1_or_user2())
{
return $this->hasMany(converstations ::class,'user1_id');
}
return $this->hasMany(converstations ::class,'user2_id');
}
I am using Laravel 5.4. I have 2 tables destination and user and a pivot table destination_user.
destination table
---|------
id | name
---|------
1 | sth
user table
---|------
id | name
---|------
1 | sth
and finally Pivot table
--------------|--------
destination_id| user_id
--------------|--------
1 | 1
2 | 1
3 | 2
I created a model for pivot table named destinationUser.
My destination model looks like this:
<?php
namespace App\models;
use App\Models\User;
use App\Models\DestinationUser;
use App\Models\DestinationImage;
use Illuminate\Database\Eloquent\Model;
class Destination extends Model
{
protected $table = 'destinations';
public function user() {
return $this->belongsToMany('App\Models\User');
}
public function destinationUser() {
return $this->hasMany('App\Models\DestinationUser');
}
}
I want to get all the destinations with their respective user detail using pivot table. I have tried so far is this:
$destinations = $this->destination->with('user', 'destinationUser')
->whereHas('destinationUser', function($query) {
$query->where('user_id', user()->id);})
->paginate(20);
dd($destinations[0]->destinationUser); gives me destination id and user id but I want user detail. How can I achieve this. Thank You for your help
You need a many to many relationship:
class Destination extends Model
{
protected $table = 'destinations';
public function destinationUser() {
return $this->belongsToMany('App\User');
}
}
controller
$destinations = $this->destination->with('destinationUser', function($query) {
$query->where('user.id', user()->id);})
->paginate(20);
As I was searching for faster execution of queries, there was a wrong design of tables. There is more load and time of execution for 3 table with pivot rather than 2 tables without pivot. So, I figured it out and corrected.
I am learning relationships in Laravel php framework and I am trying to build this query
SELECT * FROM users u INNER JOIN link_to_stores lts ON u.id=lts.user_id INNER JOIN stores s ON lts.store_id=s.store_id WHERE lts.privilege = 'Owner'
I built this in Model
Link_to_store.php
public function store()
{
return $this->belongsTo('App\Store');
}
public function user()
{
return $this->belongsTo('App\User');
}
User.php
public function store_links()
{
return $this->hasMany('App\Link_to_store');
}
Store.php
public function user_links()
{
return $this->hasMany('App\Link_to_store');
}
I tried this query but this only joins user and link_to_store table
$personal_stores = Auth::user()->store_links->where('privilege','=','Owner');
Now I am confused how to join store table too. Can anyone help with this?
Schema is like this
Stores Table
store_id store_name
Users Table
id name
Link_to_stores Table
id store_id user_id privilege
I suppose store_links is actually a pivot table. In this case, you can use belongsToMany(), this will automatically take care of the pivot table.
To do this, in your User model you change the store function to this:
function stores() {
return $this->belongsToMany('App\Store', 'store_links', 'user_id', 'store_id')->withPivot('privilege');
}
Because the primary key of stores is not id, you will have to define this in you Store model with the following line:
protected $primaryKey = 'store_id';
Now to get the stores for a user, you simply call
$stores = Auth::user->stores()->wherePivot('privilege', 'Owner')->get();
I am learning relationships in Laravel php framework and I am trying to build this query
SELECT * FROM users u INNER JOIN link_to_stores lts ON u.id=lts.user_id INNER JOIN stores s ON lts.store_id=s.store_id WHERE lts.privilege = 'Owner'
You are trying to do a join here. You can do a join like this:
$stores = User::join('link_to_stores as lts', 'users.id', '=', 'lts.user_id')->join('stores as s', 'lts.store_id', '=', 's.id')->where('lts.privilege', 'Owner')->get();
But like Jerodev pointed out, it seems like Many to Many relationship might make more sense in your case. The difference is that relationship will actually execute 2 queries (1 for original model, 1 for relationship). It will then attach the related models to the original model (which is extremely handy).
I have four tables
**Articles table**
id
title
body
owner_id
category_id
**Favorite articles table**
id
user_id
article_id
**User table**
id
user_name
user_type
**Category table**
id
category_name
How to get list of favorite articles (article_name,owner_name,category_name) which related to currently logged user from db using laravel eloquent?
Is it possible to do it in single line request? e.g.:
$articles_data=Auth::user()->favorite_articles->article...
EDIT
For the moment i have to use statement below:
$articles_data = FavoriteArticle::where('user_id', Auth::id())->join('articles', 'articles.id', '=', 'favorite_articles.article.id')
->join('users', 'users.id', '=', 'favorite_articles.user_id')
->join('categories', 'categories.id', '=', 'articles.id')
->get()
Which looks a bit complicated and doesn't use eloquent relations.
Completing #zippo_ answer, in the Controller you must reference what tables you want, e.g.
User.php
use Article;
public function article()
{
return $this->hasOne('App\Article');
}
and in the e.g. UserController.php
$user = User::with('article')->get();
EDIT:
if you want to relate User to Article.Category, after create a relation with user and article
Article.php
use Category;
public function category()
{
return $this->hasOne('App\Category');
}
e.g. UserController.php
$user_articles_categories = User::with('article.category')->get();
You can take advantage of laravel eager loading, which are also called as Eloquent relationships.
Eloquent relationships are defined as functions on your Eloquent model classes.
Eg. In Article Model
public function article()
{
return $this->hasOne('App\Model\Category');
}
In this way, you need to define all the relationships in the respective Model classes.
for more info: http://laravel.com/docs/5.1/eloquent-relationships