How to implement a self referencing (parent_id) model in Eloquent Orm - php

I have a User table and need to allow for users to have a parent user.
the table would have the fields:
id
parent_id
email
password
How would I define this self referencing relationship in Eloquent ORM?

I had some success like this, using your exact DB table.
User Model:
class User extends Eloquent {
protected $table = 'users';
public $timestamps = false;
public function parent()
{
return $this->belongsTo('User', 'parent_id');
}
public function children()
{
return $this->hasMany('User', 'parent_id');
}
}
and then I could use it in my code like this:
$user = User::find($id);
$parent = $user->parent()->first();
$children = $user->children()->get();
Give that a try and let me know how you get on!

I had a chain of self referencing contracts (a contract can be continued by another contract) and also needed self referencing. Each contract has zero or one previous and also zero or one next contract.
My data table looked like the following:
+------------------+
| contracts |
+------------------+
| id |
| next_contract_id |
+------------------+
To define the inverse of a relationship (previous contract) you have to inverse the related columns, that means setting
* foreign key column on the model table
* associated column on the parent table (which is the same table)
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Contract extends Model {
// The contract this contract followed
function previousContract()
{
// switching id and next_contract_id
return $this->belongsTo('App\Contract', 'id', 'next_contract_id');
}
// The contract that followed this contract
function nextContract()
{
return $this->belongsTo('App\Contract');
// this is the same as
// return $this->belongsTo('App\Contract', 'next_contract_id', 'id');
}
}
See http://laravel.com/docs/5.0/eloquent#one-to-one for further details.

Related

Get Information of relation table using pivot table data

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.

Getting an array from one to many relationship in Laravel using a custom key

I'm learning Laravel right now and I'm stumped on how to get an array of records from one table that belong to a record on another table based on a key.
I have two tables:
titles
-------------------
id | title_name | created_at | updated_at
posts
-------------------
id | titles_id | content
I have the route /{title_name} being controlled by the read() method on my PagesController.php
public function read($title){
$title_name = $title;
$title_id = Title::find($title)->id;
$posts = Title::find($title)->posts;
return view('pages/read')->with([
'title_name' => $title_name,
'title_id' => $title_id,
'posts' => $posts
]);
}
But this doesn't seem to output anything. I have my models setup like this:
Title.php
class Title extends Model
{
// Table Name
protected $table = "titles";
// Primary Key
protected $primaryKey = "title";
// Timestamps
public $timestamps = "true";
// Custom primaryKey
public $incrementing = false;
//relationship
public function posts(){
return $this->hasMany('App\Post', 'titles_id')->orderBy('created_at', 'desc');
}
}
Post.php
class Post extends Model
{
// Table Name
protected $table = "posts";
// Primary Key
protected $primaryKey = "id";
// Timestamps
public $timestamps = "true";
//relationship
public function titles(){
return $this->belongsTo('App\Title');
}
}
I think the problem is that when I do Title::find($title)->post, laravel is trying to find posts where the titles_id = title_name, because I set title_name as the primaryKey, but I need it to be looking for the id column in the Titles table, and not the name...
Alright I will give you an example where I explain everything you do wrong.
Tables:
titles
-------------------
id | title_name | created_at | updated_at
posts
-------------------
id | title_id | content
Not titles_id but title_id, eloquent likes this more.
Your controller:
public function read($titleName){
// The first function argument is the name of the title,
// not the title model.
// Also don't use snake_case in laravel(Except helpers) but camelCase.
// We are not going to use find, you might have set the name as
// primary key, but the id column still exists.
// firstOrFail() means get the first result, if there isn't, throw
// a model not found exception(404).
$title = Title::where('name', $titleName)->firstOrFail();
return view('pages/read')->with([
// You could just do 'title' => $title, and do the rest in the view.
'title_name' => $title->name,
'title_id' => $title->id,
'posts' => $title->posts
]);
}
Title model:
class Title extends Model
{
// $table not needed, laravel knows this(Yes pure magic).
// No, we don't want name as primary key.
// Timestamps is true by default, so we don't need it.
public function posts(){
return $this->hasMany(\App\Post::class)->orderBy('created_at', 'desc');
}
}
Post model:
class Post extends Model
{
// This function should be called title, not titles.
public function title(){
return $this->belongsTo(App\Title::class);
}
}

Relations Laravel 4 with 3 tables using Eloquent

I want to make a relation with 3 table using ORM but cant. My tables
User table
id | userame | name |
1 Ellie Elen
2 Pol Paul
record table
id | user_id| item_id| hour|
1 2 1 3
2 2 2 5
Item table table
id | title
1 item 1
2 item 2
I am using this logic but not work properly
class User Extends Eloquent {
public function record()
{
return $this->hasMany('VolunteerRecord');
}
}
class VolunteerRecord Extends Eloquent {
function item() {
return $this->hasMany('VolunteerItem');
}
}
I cant understand how to do it?
It seems like you want a Many-To-Many relationship between Users and Items but you also want to track hours on the pivot table. So first, you'll define the many-to-many relationships using belongsToMany(), and you'll tell Laravel that you have extra data on your pivot table with the withPivot() function. Your classes will look like this:
class User extends Eloquent {
protected $table = 'users';
public function items() {
return $this->belongsToMany('Item', 'records')->withPivot('hour');
}
}
class Item extends Eloquent {
protected $table = 'items';
public function users() {
return $this->belongsToMany('User', 'records')->withPivot('hour');
}
}
Then, to access the hour field you would do this:
$user = User::first(); // First User
$item = $user->items()->first(); // User's first Item
$hour = $item->pivot->hour; // The 'hour' on the User-Item relationship
Also, your current column naming scheme is correct for Laravel so don't feel like you need to change it. If you change your column names, then you'll need to define them in the belongsToMany() method like this:
$this->belongsToMany('ModelName', 'pivot_table', 'foreign_key', 'other_key');
// For example, in Items::users() you would have this:
$this->belongsToMany('User', 'records', 'users_id', 'items_id');
Finally, I'm assuming that your tables are named users, items, and records. If they are not, then just replace all instances of users, items, and records with your actual table names.
Based on your table names, I'd suggest the following, first of all, change your record table as follows:
id | users_id| items_id| hour|
1 2 1 3
2 2 2 5
And these are the classes for your models:
class Users extends Eloquent
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
public function records()
{
return $this->hasMany('Records');
}
}
class Records extends Eloquent
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'records';
public function record()
{
return $this->hasOne('Users');
}
public function item()
{
return $this->hasOne('Items');
}
}
class Items extends Eloquent
{
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'items';
public function records()
{
return $this->hasMany('Records');
}
}
These contain the relations for your models.
If you were to select a few records, for each record you can get the user and the item. If you were to select an item, and all records for that item. You can also get the user for each record.
In User Model
public function images()
{
return $this->belongsToMany('Item')->withPivot('hour');
}
In user controller
public function view($username)
{
$user = User::where('name',$username)->firstOrFail();
return View::make('view')->with('user',$user);
}
In view
#foreach ($users->items as $item)
name: {{$image->title}}<br>
hour: {{$image->pivot->hour}}<br>
#endforeach

Has many through

A Venue has many Subscriptions.
A Subscription has many Subscribers (User).
Theres a pivot table, containing the relation between user_id and subscription_id.
How can I get all Subscribers from a Venue?
I have tried with:
class Venue {
/**
* Members
*/
public function members() {
return $this->hasManyThrough('App\User', 'App\Subscription');
}
}
But it fails with MySQL error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'users.subscription_id' in 'on clause' (SQL: select `users`.*, `sub
scriptions`.`venue_id` from `users` inner join `subscriptions` on `subscriptions`.`id` = `users`.`subscription_id` where `
users`.`deleted_at` is null and `subscriptions`.`venue_id` = 1)
How my Subscription model look:
`Subscription`
class Subscription extends Model {
protected $table = 'subscriptions';
/**
* Subscripers
*/
public function subscribers() {
return $this->belongsToMany('App\User');
}
/**
* Venue
*/
public function venue() {
return $this->belongsTo('Venue');
}
}
Simple question: Why are you using a third model for Subscriptions? It sounds like a normal n:m relation between User and Venue, as already written in the comments above.
class User {
public function venues() {
return $this->belongsToMany('App\Venue');
}
}
class Venue {
public function users() {
return $this->belongsToMany('App\User');
}
}
This constellation actually needs three tables, which are (i gave each model a column name):
users
- id
- name
venues
- id
- name
user_venue
- user_id
- venue_id
But to access the relations, you can simply use the Eloquent magic:
// List of all venues (as Venue models) that are in relation with User with id $id
$venues = User::find($id)->venues()->get();
// Returns the alphabetically first user that has a relation with Venue with id $id
$user = Venue::find($id)->users()->orderBy('name', 'asc')->first();
If you need to store additional information in the pivot table (e.g. when the relation has been established), you can use additional pivot fields:
user_venue
- user_id
- venue_id
- created_at
class User {
public function venues() {
return $this->belongsToMany('App\Venue')->withPivot('created_at');
}
}
class Venue {
public function users() {
return $this->belongsToMany('App\User')->withPivot('created_at');
}
}
// Returns the date of the relations establishment for the alphabetically
// first Venue the User with id $id has a relation to
$created_at = User::find($id)->venues()->orderBy('name', 'asc')->first()->pivot->created_at;
I've never tried to do whatever you are trying to do there, because it seems (with the current information) conceptually wrong. I also don't know if it is possible to set up an own model for a pivot table, but I think it should work if the pivot table has an own primary id column. It could probably be helpful if you've a third model that needs to be connected with a connection of two others, but normally that doesn't happen. So try it with pivot tables, like shown above, first.
Alright, I still don't see a good use case for this, but I can provide you a query that works. Unfortunately I wasn't able to get an Eloquent query working, but the solution should be still fine though.
class Venue {
public function members($distinct = true) {
$query = User::select('users.*')
->join('subscription_user', 'subscription_user.user_id', '=', 'users.id')
->join('subscriptions', 'subscriptions.id', '=', 'subscription_user.subscription_id')
->where('subscriptions.venue_id', '=', $this->id);
if($distinct === true) {
$query->distinct();
}
return $query;
}
}
The relation can be queried just as normal:
Venue::find($id)->members()->get()
// or with duplicate members
Venue::find($id)->members(false)->get()

laravel eloquent relationships queries

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';

Categories