Multiple level hasManyThrough relationship with Eloquent - php

I'm using Eloquent in my PHP application and struggling with a hasManyThrough relationship.
Here's my structure :
Company
id
name
Admin
id
company_id
name
Offer
id
admin_id
name
Application
id
offer_id
candidat_id
Each Admin is part of a Company and can post Offer's, and the candidats can make an Application on that offer.
I'm trying to fetch all the applications that have been made on offers that have been started by admins of that company.
I've tried using the hasManyThrough relationship in my Company model, like so :
public function applications()
{
return $this->hasManyThrough("Application", "Offer");
}
but I get the following error :
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'offers.entreprise_id' in 'field list' (SQL: select `applications`.*, `offers`.`entreprise_id` from `applications` inner join `offers` on `offers`.`id` = `applications`.`offer_id` where `offers`.`entreprise_id` in (1))
Which makes sense, since it's thinking that the Offer is listed to the Company and not to the Admin.
How can I set it up so that it will look for the Admin's of that company, without having to fetch all the admins of the company and then looping through them, getting all the applications for each admins?
This would work, but it seems like a tedious way of doing it when Eloquent provides these relationships that make our lives easier. Is there a more elegant way of achieving what I want?

There is no native relationship for this case.
I created a HasManyThrough relationship with unlimited levels: Repository on GitHub
After the installation, you can use it like this:
class Company extends Model {
use \Staudenmeir\EloquentHasManyDeep\HasRelationships;
public function applications() {
return $this->hasManyDeep(Application::class, [Admin::class, Offer::class]);
}
}

Related

How to create pivot table for two users (teachers, students) accessing the same Course table as asiggned to and enrolled to using Laravel

I have an issue in creating the database structure to be supported by laravel on the above subject.
The structure of my tables is this.
Users Table:
Name
Type
Email
Password
Course
Name
Description
I am using a single users table to authenticate both teachers and students whenever they log in to the system. The column "Type" is used to define the user type i.e. admin, teacher and student.
Now the issue comes. The system requirements are:
Requirements
Course lists showing the assigned teachers on the course
Teachers are assigned the courses by admins
Teachers enroll the students to their class
Students will see their courses after being enrolled showing the course teacher too.
How can I build a pivot table for this scenario in laravel, because according to my idea this is what I have in mind.
course_user
course_id
user_id
But am failing how to identify that this course is assigned to this teacher, and this teacher has enrolled this student to this particular course using the same pivot table.
Please help enlighten me up.
Thanks....
Create two relation functions with additional filer like this:
class Course extends Model
{
...
public function teachers()
{
return $this->belongsToMany(User::class)->where('type', '=', User::TEACHER);
}
public function students()
{
return $this->belongsToMany(User::class)->where('type', '=', User::STUDENT);
}
}
I assume that you use class constants in User class.

Laravel Eloquent - How to define such a relationship: Comment::language()->name

The languages table has: id, shortcode
The comments table has id, user_id, comment, language_id (foreign key)
In the Comment Model I defined Language as a hasOne Relationship
In the Language Model I defined Comments as a hasMany Relationship (this is wrong?).
In Tinker I get this error when I try to execute: $comment->language()->get():
Column not found: 1054 Unknown column 'languages.comment_id' in 'where clause' (SQL: select * from `languages` where `languages`.`comment_id` = 7 and `languages`.`comment_id` is not null)'
Why is Laravel searching in the languages table for the comment_id? It seems I misunderstand something completely.
What is the right way to do get the language shortcode? I thought $comment->language()->shortcode should work.
And what is the most efficient way to preload all the language_id and shortcode information without performing duplicate queries since this is used a lot?
Laravel makes assumptions on your key-names in your relationship. Because you use the hasOne relationship, Laravel expects the key to be in the languages table, named comment_id.
Your Comment model should use a belongsTo relationship to Language and drop the hasOne. This way laravel makes the assumption that the foreign-key is actually in the comments table, named language_id, which is the case :).
Using the belongsTo relationship solved the problem.
Afterwards I could access it with $comment->language->shortcode;
thanks everyone!

Fundamental misunderstanding of model in Eloquent (Outside of Laravel)

So I've been struggling with using basic eloquent in Slim Framework 2 for quite a while now. This is not my first Eloquent question, but I'm hoping this one actually can be answered unlike my previous one: Using polymorphic relationships in Eloquent to extend model
I'm working on a simple chemical database for tracking for my University. I've got the Chemicals table with column company_id that correlates to a table called company with just 2 columns, id and company. chemicals.company_id is a foreign key referencing company.id.
(This, along with several others, like room, and location, started out as Enums, but it quickly became apparent the users would need to be able to add to them. Editing a DB column to add an enum is obviously not a practical idea.)
In Chemical I have:
public function company()
{
return $this->hasOne('Lab_Chemicals\Chemical\company');
}
And in Company I have:
public function chemical()
{
return $this->belongsTo('Lab_Chemicals\Chemical\chemical');
}
They're both in the same namespace (Lab_Chemicals\Chemical) and on their own I can do a
$chemicals = $app->chemical->get();
and
$company = $app->company->get();
and get the proper list so the basics appear to be setup correctly, but if I try to do this:
$company = chemical::find(1)->company;
I get Slim Application Error:
Type: Illuminate\Database\QueryException
Code: 42S22
Message: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'company.chemical_id' in 'where clause' (SQL: select * from company where company.chemical_id = 1 and company.chemical_id is not null limit 1)
Which brings me to my real question. Isn't this backwards? Why is it looking for chemical_id in company? I know that this is what it says it does in the docs
https://laravel.com/docs/4.2/eloquent#relationships: "Take note that Eloquent assumes the foreign key of the relationship based on the model name. In this case, Phone model is assumed to use a user_id foreign key."
I'd expect it to look for the company where chemical.company_id = company.id. Where is the flaw in my way of thinking and what can I do to make it work as expected?
Thanks

get *related* linked models in laravel eloquent instead of raw SQL

I'm trying to get 'related' linked models by querying a link table, named company_projects which holds (as you expect) the id's of companies and projects (projects are kind of product-categories).
In this case, the used flow to determine a related project is:
Get companies who are in the same project ('product category') as you
Find the other project id's which are linked to those companies
Get the info of the linked projects fetched by last step
What i'm trying to do is already functional in the following raw query:
SELECT
*
FROM
projects
WHERE
projects.id IN
(
SELECT cp1.project_id
FROM company_projects cp1
WHERE cp1.company_id IN
(
SELECT cp1.company_id
FROM projects p
LEFT JOIN company_projects cp2 ON cp2.project_id = p.id
WHERE p.id = X AND cp2.company_id != Y
)
)
AND projects.id != X
X = ID of current project ('product category')
Y = ID of current 'user' (company)
But my real question is, how to do this elegantly in Laravel Eloquent (currently v4.2). I tried it, but I have no luck so far...
Update:
I should note that I do have experience using Eloquent and Models through multiple projects, but for some reason I just fail with this specific query. So was hoping to see an explained solution. It is a possibility that I'm thinking in the wrong way and that the answer is relatively easy.
You will need to utilize Eloquent relationships in order to achieve this. (Note that I am linking to the 4.2 docs as that is what you are using, but I would highly suggest upgrading Laravel to 5.1)
I am assuming you have a 'Company' and 'Project' model already. Inside each of those models, you need to a define a method that references its relationship to the other model. Based on your description, it sounds like the two have a Many to Many relationship, meaning that a company can have many projects and a project can also belong to many companies. You already have a database table linking the two. In the Eloquent ORM this linking table is called a pivot table. When you define your relationships in the model, you will need to pass the name of that pivot table as your second argument. Here's how it could look for you.
Company model:
class Company extends Model
{
/**
* Get the projects attached to a Comapny. Many To Many relationship.
*/
public function projects()
{
return $this->belongsToMany('Project','company_projects');
}
}
Project model:
class Project extends Model
{
/**
* Get the companies this project belongs to. Many To Many relationship.
*/
public function companies()
{
return $this->belongsToMany('Company','company_projects');
}
}
If your models have these relationships defined, then you can easily reference them in your views and elsewhere. For example, if you wanted to find all of the projects that belong to a company with an ID of 1234, you could do this:
$company = Company::find(1234);
$projects = $company->projects;
Even better, you can utilize something called eager loading, which will reduce your data lookup to a single line (this is mainly useful when passing data to views and you will be looping over related models in the view). So those statements above could be rewritten as:
$company = Company::with('projects')->find(123);
This will return your Company model with all its related products as a property. Note that eager loading can even be nested with a dot notation. This means that you can find all the models that link to your main model, and then all the models for those models, and so on and so forth.
With all of this in mind, let's look at what you specifically want to accomplish.
Let us assume that this method occurs in a Controller that is being passed a project id from the route.
public function showCompaniesAndProjects($id)
{
//Get all companies in the same project as you
//Use eager loading to grab the projects of all THOSE companies
//Result will be a Project Object with all Companies
//(and those projects) as Eloquent Collection
$companies = Project::with('companies.projects')->find($id);
//do something with that data, maybe pass it to a view
return view('companiesView')->with('companies',$companies);
}
After defining your relations in your models, you can accomplish that whole query in a single line.

Laravel Eloquent, how to select users of certain type from many to many relationship

I am a extreme beginner at Laravel. Looked at the documentation on the website and have managed to create a many to many relation of classes and users.
Tables structure
Users
Classes
Users_Classes
Users table
users_id
users_type 'student','teacher'
Classes table
class_id
class_name
Uses_Classes table
user_id
class_id
Classroom Model
<?php
public function getStudents() {
return $this->belongsToMany('User', 'cla_use_relationship', 'cla_class_id', 'use_users_id');
}
?>
Admin Controller
$students = Classroom::find(1)->getStudents;
So the students variable is populated with users where class id = 1. What I need though is all the users of type student. So far its getting all users. I tried doing a where function but no users were returned.
Is there any good resources on beginners understanding laravel, especially the Eloquent side of it, understanding what functions work with what.
After your belongsTo you can chain a where clause to restrict it to just students, something like
public function getStudents() {
return $this->belongsToMany('User', 'cla_use_relationship', 'cla_class_id', 'use_users_id')
->where('users_type', 'student');
}
For getting into the basics of laravel, I'd recommend checking out the resources on the main docs page: http://laravel.com/docs#additional-resources
Code Bright would probably be the best for a beginner, then work your way up from there.

Categories