Laravel 4 - Models & One to Many - php

I'm trying to get my head around laravel models & one to many...
I have the following tables
ww_bookings
-----------------------------
booking_id
customer_id
quote_id
ww_quotes
-----------------------------
quote_id
etc
etc
etc
I'm using sentry for my auth and basically on a sucsessful login I want to find the id of the logged in user and then query the ww_bookings data WHERE customer_id = 'logged in user id'.
Once it's good all the bookings for the customer_id it then need to go and query ww_quotes for each booking found and bring back the data.
//Controller
BookingData::find(1)->quotes()->where('quote_id', '=', '1')->get();
//BookingData Model
class BookingData extends Eloquent {
protected $table = 'ww_bookings';
protected $primaryKey = 'customer_id';
public function quotes() {
return $this->hasMany('QuoteData');
}
}
//QuoteData Model
class QuoteData extends Eloquent {
protected $table = 'ww_quotes';
}
I get the following error:
Column not found: 1054 Unknown column 'ww_quotes.booking_data_id' in 'where clause' (SQL: select * from ww_quotes where ww_quotes.booking_data_id = 1 and quote_id = 1)
Can anyone help me out, it's been driving me crazy...
Hope it makes sense..

There are two problems I see:
Wrong relationship
The problem is that ww_quotes schema/table should contain key that refers ww_booking schema/table - exactly in reverse.
Solution to this:
ww_bookings
-----------------------------
customer_id
quote_id
ww_quotes
-----------------------------
quote_id
booking_id
Key will not match
Key names that Eloquent generates and uses for relations will not match existing key names. If you specify them, Eloquent use them instead.
return $this->hasMany('QuoteData', 'booking_id');

Related

Laravel Eloquent finding models with more than one relation to another model on another table [duplicate]

This question already has answers here:
laravel BelongsTo relationship with different databases not working
(13 answers)
Closed 2 years ago.
I have two models using different tables on two different connections, User and UserInfo.
User has a UserInfo hasMany relation:
public function userInfo()
{
return $this->hasMany('path\to\UserInfo','User_ID');
}
and UserInfo has a User belongsTo relation:
public function user()
{
return $this->belongsTo('anotherpath\to\User', 'User_ID', 'User_ID');
}
I would like to find the first user with more than one UserInfo, however I believe that because they are on different tables on the database I am having issues.
This call
$patient = Patient::with('UserInfo')
->withCount('UserInfo')
->having('UserInfo_count', '>', 1)
->first();
Works as expected for other relations and is what I am trying to achieve, but not with this one. The difference being that the two models are on different tables. When I call this in Tinker, I get the error:
Illuminate/Database/QueryException with message 'SQLSTATE[42S02]:
Base table or view not found: 1146 Table '(TableName).UserInfo'
doesn't exist (SQL: select `User`.*, (select count(*) from `UserInfo`
where `User`.`User_ID` = `eob`.`User_ID`) as `UserInfo_count `User`
having `UserInfo_count` > 1 limit 1)'
Any ideas? I'm very new to eloquent and Laravel in general, sorry if I've gotten any terminology wrong or am missing something simple. Thanks!
maybe your table names are not defined properly as standard. so you can use table property to bind table name in model.
what is the standard to define table name.
Illuminate/Database/Eloquent/Model.php
/**
* Get the table associated with the model.
*
* #return string
*/
public function getTable()
{
if (isset($this->table)) {
return $this->table;
}
return str_replace('\\', '', Str::snake(Str::plural(class_basename($this))));
}
Example
Table Model
users User
user_profiles UserProfile
Alternative
in your UserInfo model
protected $table = 'your table name';
In more thing you don't need to add with() method and with withCount() method.
$patient = Patient::withCount('UserInfo')->having('UserInfo_count', '>', 1)->first();

Laravel Model Relationship on Non-Static Tables

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!

Retrieve distant relation through has-many-through for many-to-many relation in Laravel

I have the following models in my application
User
Group
Task
which have the following relationships
User and Group have a many-to-many relationship
Task and Group have a many-to-many relationship
So basically a user can belong to more than one group and each group can have more than one task.
Following is the table structure.
users
id
name
groups
id
name
tasks
id
name
group_user
id
group_id (foreign key with groups table)
user_id (foreign key with users table)
group_tasks
id
group_id (foreign key with groups table)
task_id (foreign key with tasks table)
Now I want to retrieve all the tasks for the user.
I tried the following approaches and both didn't work.
Approach 1
$user->groups() gives the list of groups for a user
$group->tasks() gives the list of tasks for a group
So I tried
$user->groups()->tasks() but it didn't work.
Approach 2
I tried Has Many Through by adding this to my User model
public function tasks()
{
return $this->hasManyThrough(Task::class, Group::class);
}
but even that didn't work. The following is the error that I am getting
QueryException in Connection.php line 713:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'groups.user_id' in 'field list' (SQL: select `tasks`.*, `groups`.`user_id` from `tasks` inner join `groups` on `groups`.`id` = `tasks`.`group_id` where `groups`.`user_id` = 1)
My guess is that this is happening because it is expecting one-to-many relationship, but I have a many-to-many relationship.
So is there a way to retrieve it without getting all groups and then looping through them?
User Model
public function groups()
{
return $this->belongsToMany('App\Group');
}
Group Model
public function tasks()
{
return $this->belongsToMany('App\Task');
}
Task Model
public function groups()
{
return $this->belongsToMany('App\Group');
}
Retrieving all tasks for a user.
$user = User::find(1);
$user->load('groups.tasks');
$tasks = $user->groups->pluck('tasks')->collapse();
You can also take a look at the extension of the HasManyThrough here: https://github.com/staudenmeir/eloquent-has-many-deep
It helps you to retrieve many sub-levels of your relationships.
In your case, it would be
User -> belongsToMany(Groups) -> blongsToMany (Tasks)
just add your method to the user model like:
public function tasks()
{
return $this->hasManyDeep(
'App\Task',['App\Group']
);
}

Laravel 4 Eloquent Relationship

I have 2 tables:
`tasks {id, task_name, status_id}`
`statuses {id, status_name }`
A task can only have one status at a time eg Pending, Active, Completed, Aborted, etc
This is what I have so far.
class Task extends Eloquent
{
public function status
{
return $this->hasOne('Status', 'id');
}
}
When I try $task->status->status_name, I get 'Trying to get a property of non object' error!
My Status class looks like this
class Status extends Eloquent
{
protected $table = 'statuses';
}
Could you explain why I'm having this error?
Since you got the foreign key in Task table, you can use belongsTo and Eloquent will look for column status_id in tasks table for you.
public function status
{
return $this->belongsTo('Status');
}
for more information http://laravel.com/docs/4.2/eloquent in One to One section
For the error Trying to get a property of non object
Please make sure there is a value in column status_id on table tasks on very record.

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