Manytomany relation in Laravel - php

I'm working in Laravel and need help with database relations. I have three tables:
projects:
+------------+--------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(191) | NO | | NULL | |
| url | varchar(191) | YES | | NULL | |
| updated | bigint(20) unsigned | YES | | NULL | |
| type | enum('adobe','invision','pdf') | NO | | NULL | |
| preview_id | int(10) unsigned | YES | MUL | NULL | |
+------------+--------------------------------+------+-----+---------+----------------+
users:
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| email | varchar(150) | NO | UNI | NULL | |
| password | varchar(179) | NO | UNI | NULL | |
| remember_token | varchar(100) | YES | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
projects_users
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| project_id | int(10) unsigned | YES | MUL | NULL | |
| user_id | int(10) unsigned | NO | MUL | NULL | |
+------------+------------------+------+-----+---------+----------------+
Situation: There are several projects, and multiple users can work on multiple projects (ManyToMany).
I need to select (SELECT-statement) all users working on project with e.g ID 1.
How would I do that in plain SQL, and how would I do that in Laravel code (without a raw-sql-query function).
I already looked here but I ain't really catching it.
Thanks!

Use the whereHas() method:
$users = User::whereHas('projects', function($q) use($projectId) {
$q->where('id', $projectId);
})->get();

class Project extends Model{
public function users()
{
return $this->belongsToMany('App\User', 'projects_users');
}
}
class User extends Model{
public function projects()
{
return $this->belongsToMany('App\Project', 'projects_users');
}
}
$project = Project::find(1);
$project->users //list of all the users

Related

query relation always null with model_type value single slash Laravel 9

I have a trouble with relationship on laravel 9 with code detail below:
namespace App\Models;
use App\Traits\HasMeta
class PostModel extends Model{
use HasMeta;
}
namespace App\Traits;
use App\Models\MetaModel;
trait HasMeta{
public function meta() {
return $this->morphOne(MetaModel::class, 'metas', 'model_type', 'model_id') ;
}
}
And my schemas is:
+---------------------+-------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| model_id | int(11) | NO | MUL | NULL | |
| model_type | varchar(255) | NO | | NULL | |
| meta_slug | varchar(255) | NO | UNI | NULL | |
| meta_title | varchar(255) | YES | | NULL | |
| meta_description | text | YES | | NULL | |
| meta_keywords | text | YES | | NULL | |
| meta_canonical | varchar(255) | YES | | NULL | |
| meta_index | enum('index','noindex') | NO | | noindex | |
| meta_og_title | varchar(255) | YES | | NULL | |
| meta_og_description | text | YES | | NULL | |
| meta_tw_title | varchar(255) | YES | | NULL | |
| meta_tw_description | text | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+---------------------+-------------------------+------+-----+---------+--------------
But when i used method $post->meta()->save(array $data) -> it's ok and insert to database with value
+----+----------+----------------------+
| id | model_id | model_type |
+----+----------+----------------------+
| 1 | 83 | App\Models\PostModel |
+----+----------+----------------------+
However when i used $post->meta --> it always return null.
My sql laravel output:
select * from `ord_metas` where `ord_metas`.`model_id` in (83) and `ord_metas`.`model_type` = 'App\Models\PostModel'
If model_type with double slash like 'App\\Models\\PostModel' --> it will be ok on mysql query
How can i fix it. Thank for reading and sorry for my bad english
Make a method inside the MetaModel like
public function metable ()
{
return $this->morphTo();
}
and make another method inside your trait or postModel like
public function meta()
{
return $this->morphOne(MetaModel::class , 'metable');
}
Now you can load the relationship as $post->meta Hope this helps you.

Laravel one-to-many relationship with different column than primary key

I have following two tables:
account:
+--------------------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+---------------------+------+-----+---------+-------+
| id | varchar(25) | NO | PRI | | |
| name | varchar(191) | NO | UNI | NULL | |
| status | tinyint(3) unsigned | NO | | NULL | |
| active | tinyint(3) unsigned | NO | | NULL | |
project:
+-----------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| client_code | varchar(191) | NO | | NULL | |
| tags | varchar(500) | YES | | NULL | |
| project_id | int(11) | NO | | NULL | |
| file_name | varchar(191) | NO | | NULL | |
| total_records | int(11) | NO | | NULL | |
There's a one-to-many relationship between account and projects.
Foreign key in projects table is named account_code instead of account_id.
The issue being project identifier column that is of significance is project_id rather than id in projects table.
Here's my Account model:
public function projects() {
return $this->hasMany('App\Project', 'account_code');
}
Project model:
public function account() {
return $this->belongsTo('App\Account', 'account_code', 'project_id');
}
I have a row in projects table as:
id: 9
account_code: 0011T00002K95MLQAZ
tags: cpi|test|dmf
project_id: 312
file_name: conf_matrix_dev_1579064650.tsv
total_records: 19
I tried retrieving account detail that project_id 312 belongs to.
$project = \App\Project::where('project_id', 312)->get();
dd($project->account->name);
This throws exception:
Property [account] does not exist on this collection instance
and with this:
$project = \App\Project::find(312);
this tried to look into by id field instead of project_id.
How can I solve this without having to write a query?
The problem here is that get is retrieving you a collection instead of an instance. You can use
$project = \App\Project::where('project_id', 312)->first();
instead and that should do the trick.
Hope it helps. Some other solutions are exposed here: Property [title] does not exist on this collection instance

Laravel eloquent many to many returns empty

So i'm trying to get my head around using eloquent for many to many relationships in my application.
I have three tables as followed
user
+----------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| first_name | varchar(255) | NO | | NULL | |
| last_name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| password | varchar(60) | NO | | NULL | |
| remember_token | varchar(100) | YES | | NULL | |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| active | enum('yes','no') | NO | | NULL | |
| last_login | timestamp | NO | | 0000-00-00 00:00:00 | |
+----------------+------------------+------+-----+---------------------+----------------+
user_has_address
+------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+-------+
| address_id | int(10) unsigned | YES | MUL | NULL | |
| users_id | int(10) unsigned | YES | MUL | NULL | |
+------------+------------------+------+-----+---------+-------+
address
+---------------+----------------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+----------------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name_number | varchar(45) | NO | | NULL | |
| first_line | varchar(45) | NO | | NULL | |
| second_line | varchar(45) | NO | | NULL | |
| town_city | varchar(45) | NO | | NULL | |
| state_country | varchar(45) | NO | | NULL | |
| post_zip | varchar(45) | NO | | NULL | |
| type | enum('delivery','billing') | NO | | NULL | |
| created_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| deleted_at | timestamp | YES | | NULL | |
+---------------+----------------------------+------+-----+---------------------+----------------+
in my user repository i have the following
namespace App\Libraries\Repositories\Core\Users;
use Schema;
use App\Models\Core\User;
use Bosnadev\Repositories\Eloquent\Repository;
use Symfony\Component\HttpKernel\Exception\HttpException;
class UserRepository extends Repository
{
public function getUsersAddresses()
{
return $this->userModel->hasManyThrough('App\Models\Bundle\Addresses\Address','App\Models\Bundle\Addresses\UserHasAdress','id','address_id');
}
}
Im returned an object that shows parent and related classes but im not actually returned my users address. Is there something im missing?
Alexrussell made some good points in his comment that you could possibly address, however I believe your immediate problem is a missing ->get() at the end of your return line.
Without it, you would be required to call your method like:
$repository->getUsersAddresses()->get();
As hasManyThrough will return an instance of Illuminate/Database/Eloquent/Relations/HasManyThrough not the actual results
For reference:
https://laravel.com/api/5.2/Illuminate/Database/Eloquent/Relations/HasManyThrough.html
Note in the example here: https://laravel.com/docs/5.1/eloquent-relationships#many-to-many
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
/**
* The roles that belong to the user.
*/
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
The example usage includes a get(): $roles = App\User::find(1)->roles()->orderBy('name')->get();
Hope this helps

Complex join using eloquent

I have three models:
Vehicles:
+--------------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| registration | varchar(255) | NO | | NULL | |
| vin | varchar(255) | NO | | NULL | |
| titular_id | int(10) unsigned | NO | | NULL | |
| titular_type | varchar(255) | NO | | NULL | |
| renter_id | int(10) unsigned | NO | | NULL | |
| renter_type | varchar(255) | NO | | NULL | |
+--------------------+------------------+------+-----+---------------------+----------------+
SiretCompanies:
+------------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| siret | varchar(255) | NO | | NULL | |
| siren_company_id | int(10) unsigned | NO | MUL | NULL | |
+------------------+------------------+------+-----+---------------------+----------------+
SirenCompany:
+---------------------+------------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+------------------+------+-----+---------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| siren | varchar(255) | NO | | NULL | |
+---------------------+------------------+------+-----+---------------------+----------------+
A vehicle can be related to the SirenCompany either through a titular, or a renter. What I want is to get all related vehicles for a SirenCompany.
In raw MySQL, this is my query:
select count(*) FROM `vehicles`
inner join `siret_companies`
on (
(`vehicles`.`titular_type` = 'SiretCompany' and `vehicles`.`titular_id` = `siret_companies`.`id`)
OR
(`vehicles`.`renter_type` = 'SiretCompany' and `vehicles`.`renter_id` = `siret_companies`.`id`)
)
inner join `siren_companies`
on `siren_companies`.`id` = `siret_companies`.`siren_company_id`
where `siren_companies`.`id` = 410
Now what I would like to do is run that as an Eloquent query, but I cannot seem to figure it out.
If I only consider the titular, I have this:
return Vehicle::join('siret_companies',function($join) {
$join
->where('vehicles.titular_type', '=', 'SiretCompany')
->where('vehicles.titular_id','=', 'siret_companies.id');
})
->join('siren_companies', function($join) {
$join->on('siren_companies.id', '=', 'siret_companies.siren_company_id');
})
->where('siren_companies.id','=',$this->id)
->count();
But I cannot seem to figure out how to write the join so that it corresponds to the above query.
This is what I've come up with
Vehicle::join('siret_companies', function ($q) {
$q->on('vehicles.titular_type', '=', 'SiretCompany');
$q->orOn('vehicles.titular_id','=', 'siret_companies.id');
})->join('siret_companies', function ($q) {
$q->on('siren_companies.id', '=', 'siret_companies.siren_company_id');
})->where('siren_companies.id','=', $id);

Many to many relationships with taxonomy in Eloquent

I'm using Laravel 4. I have many to many relationships in my system. And I choose to use Wordpress taxonomy table scheme.
But how can I make models relationships with Laravel 4 Eloquent ORM? Here is my database tables;
Table terms:
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| term_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(200) | NO | MUL | | |
| slug | varchar(200) | NO | UNI | | |
+------------+---------------------+------+-----+---------+----------------+
Table term_taxonomy:
+------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------------+------+-----+---------+----------------+
| term_taxonomy_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| term_id | bigint(20) unsigned | NO | MUL | 0 | |
| taxonomy | varchar(32) | NO | MUL | | |
| description | longtext | NO | | NULL | |
| parent | bigint(20) unsigned | NO | | 0 | |
| count | bigint(20) | NO | | 0 | |
+------------------+---------------------+------+-----+---------+----------------+
Table term_relationships:
+------------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------+---------------------+------+-----+---------+-------+
| object_id | bigint(20) unsigned | NO | PRI | 0 | |
| term_taxonomy_id | bigint(20) unsigned | NO | PRI | 0 | |
| term_order | int(11) | NO | | 0 | |
+------------------+---------------------+------+-----+---------+-------+
Normally we can do return $this->belongsToMany('Term'); but how can we do 2 relationships? We need 2 relationships first find term taxonomy from "term_taxonomy" table, after find term relations with "taxonomy_id".
And an example for how I want to use;
$categories = Post::find(1)->categories; // get terms with taxonomy="post_category"
$tags = Post::find(1)->tags; // get terms with taxonomy="post_tag"
I don't want to do this with basic database class "DB::table('table')->join('...')..." I want to use Eloquent relation methods and models.
You can create getter methods to handle these:
In your Post model, create new methods something along the lines of:
public function getCategories()
{
return $this->hasMany()->where('taxonomy', 'post_category');
}
public function getTags()
{
return $this->hasMany()->where('taxonomy', 'post_tag');
}

Categories