Laravel eloquent relation error - Call to undefined relationship - php

I have two tables schools and subscriptions. I already get the school_id from my subscriptions table. My problem is when I want to get the description column from schools table. I get an error Call to undefined relationship [description] on model [App\Subscription]. Can someone tell me what is the problem of my codes? I already defined the relationship in my models and in the migration. I don't want to use querybuilder because its too confusing. Thanks.
Schools Model
class School extends Model
{
protected $fillable = ['description'];
public function user(){
return $this->hasMany('App\User');
}
public function subscriber()
{
return $this->belongsTo('App\Subscription','description');
}
}
Subscription Model
class Subscription extends Model
{
protected $fillable = [
'id', 'school_id', 'start_date', 'end_date',
];
public function subscriptions(){
return $this->hasMany('App\School','description');
}
public function plans(){
return $this->belongsTo('App\Plan');
}
}
My controller
$subs = Subscription::findOrFail($id)->with('description')
->get();
$plans = Plan::get();
dd($subs);
PS. When i only put$subs = Subscription::findOrFail($id); I get this data in dd
#attributes: array:8 [▼
"id" => 2
"school_id" => 2
"start_date" => "2019-09-27"
"end_date" => "2019-10-27"
"created_at" => "2019-10-17 03:36:13"
"updated_at" => "2019-10-17 03:36:13"
"plan_id" => 2
"status" => 1
]
Schools Table
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(191) | NO | UNI | NULL | |
| description | text | NO | | NULL | |
| logo | varchar(191) | YES | | NULL | |
| main_server | varchar(191) | YES | | NULL | |
| local_server | varchar(191) | YES | | NULL | |
| status | int(11) | NO | | 1 | |
| updated_by | varchar(191) | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+--------------+------------------+------+-----+---------+----------------+
Subscriptions
+------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| school_id | int(10) unsigned | NO | MUL | NULL | |
| start_date | date | YES | | NULL | |
| end_date | date | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| plan_id | int(10) unsigned | NO | MUL | NULL | |
| status | int(11) | NO | | NULL | |
+------------+------------------+------+-----+---------+----------------+
EDIT: I just want to get the description from school_id that i get from $subs

In Subscription Model change the relation function subscriptions
public function subscriptions(){
return $this->hasMany('App\School', 'id', 'school_id');
}
call the eloquent query to
$subs = Subscription::with('subscriptions')->findOrFail($id);
dd($subs->subscriptions[0]->description);

You call wrong relation. You have defined subscriptions and not description relation in your Subscription Model.
Maybe it's typo?
you can change your relationship to :
public function description(){
return $this->hasMany('App\School','id', 'school_id');
}
and then just call it like:
$subs = Subscription::with('description')->findOrFail($id);

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.

How to query foreign relations data along with multiple main records

I have a relation Room. Each room has one owner which is a User entity, and each Room has multiple participants which are also User entity.
When the page loads, I query all rooms in React
once all the rooms are returned back, I query the database one by one with each rooms ID to get back the details of of the room stored in other relations (Room owner, room user count, room topic which is of entity Topic)
const fetchRooms = () => {
const csrf: HTMLMetaElement = document.querySelector(
"meta[name='csrf-token']"
) as HTMLMetaElement;
axios
.post(
`/room/all/${pageNumber}`,
{},
{
headers: {
"Content-type": "application/json",
"X-CSRF-TOKEN": csrf.content,
},
}
)
.then((response) => {
const data = response.data;
data.forEach((room: any) => {
//! TODO: merge each rooms details with its own data to avoid extra requests
axios
.post(
"/room/details",
{ id: room.id },
{
headers: {
"Content-type": "application/json",
"X-CSRF-TOKEN": csrf.content,
},
}
)
.then(({ data }) => {
if (data) {
setRooms((rooms) => [
...rooms,
<RoomCard
key={room.id}
id={room.id}
title={room.name}
img={null}
username={data.owner.username}
timestamp={room.created_at}
userCount={data.user_count}
topic={data.topic.name}
/>,
]);
}
});
});
})
.catch(({ response }) => {
console.log(response.status, response.data);
});
};
which laravel handles
// web.php
Route::controller(RoomController::class)->group(function () {
Route::post("room/all/{page:int}", "all")->name("rooms.all");
Route::post("room/details", "details")->name("rooms.details");
}
// RoomController.php
public function all(Request $request, $page = 1)
{
if (!Auth::check()) {
return response("", 403);
}
$total_posts = 20;
$rooms = Room::offset(($page - 1) * $total_posts)->limit($total_posts)->orderBy("id", "desc")->get();
return response()->json($rooms);
}
public function details(Request $request)
{
if ($request->id) {
$room = Room::find($request->id);
$user_count = RoomUser::where("room_id", $room->id)->count() + 1;
return response()->json(["owner" => $room->owner, "user_count" => $user_count, "topic" => $room->topic]);
}
return response("", 403);
}
DB info
+------------------------+
| Tables_in_project |
+------------------------+
| failed_jobs |
| migrations |
| password_resets |
| personal_access_tokens |
| room_users |
| rooms |
| topics |
| users |
+------------------------+
Users
+-------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| username | varchar(255) | NO | UNI | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| email_verified_at | timestamp | YES | | NULL | |
| password | varchar(255) | NO | | NULL | |
| remember_token | varchar(100) | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| profile_picture | varchar(255) | YES | | NULL | |
| privilege_level | int(11) | NO | | 0 | |
+-------------------+---------------------+------+-----+---------+----------------+
Rooms
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| description | text | YES | | NULL | |
| topic_id | bigint(20) unsigned | NO | MUL | NULL | |
| owner_id | bigint(20) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
Topics
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
| name | varchar(255) | NO | UNI | NULL | |
+------------+---------------------+------+-----+---------+----------------+
Users in rooms
+------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| room_id | bigint(20) unsigned | NO | MUL | NULL | |
| user_id | bigint(20) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+------------+---------------------+------+-----+---------+----------------+
The problem that I'm experiencing is that, this is very VERY inefficient, as I have to query the details of the room separately for EACH room, this is going to be very slow after its deployed, it's even slow in my local machine.
I'm unsure as how to deal with it.
The one route I'm aware of is using relations provided by Laravel but then there's another problem
When I query all rooms, I return them as it is back. The user model functions (the functions that access the one to one and one to many etc relations) are only available in Laravel, of course they are not sent back with the response to JS.
How can I query rooms table and include all the information relating the room (topic, owner, all users that are in the room; their IDs are stored in room_users, all users count)
I'm using:
ReactJS 17.0.2
Laravel 9
PHP 8.1
MySQL Ver 15.1 Distrib 10.7.3-MariaDB
Thanks to aynber for helping in comments.
I solved it by using with function in eloquent.
In all function of RoomController I changed the query to
$rooms = Room::with(["topic", "owner", "users"])->offset(($page - 1) * $total_posts)->limit($total_posts)->orderBy("id", "desc")->get();
The array passed to with needs to have function names defined in model of Room which are as following in my case
public function topic()
{
return $this->belongsTo(Topic::class);
}
public function owner()
{
return $this->belongsTo(User::class);
}
public function users()
{
return $this->belongsToMany(User::class, "room_users");
}

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

Yii 1.1: Fetching HAS_MANY between two models

Our platform is build using Yii 1.1. We have users with staff role, and they have permissions granted to them.
client_staff
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| code | varchar(20) | YES | | NULL | |
| clientId | int(11) unsigned | NO | MUL | NULL | |
| emailAddress | text | NO | | NULL | |
| firstName | varchar(45) | YES | | NULL | |
| lastName | varchar(45) | YES | | NULL | |
| archivedAt | datetime | YES | | NULL | |
| createdAt | datetime | YES | | NULL | |
| updatedAt | datetime | YES | | NULL | |
+--------------+------------------+------+-----+---------+----------------+
staff_permissions
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| code | varchar(20) | YES | UNI | NULL | |
| staffId | int(11) unsigned | NO | MUL | NULL | |
| permissionId | int(11) unsigned | NO | MUL | NULL | |
| createdAt | datetime | YES | | NULL | |
| updatedAt | datetime | YES | | NULL | |
+--------------+------------------+------+-----+---------+----------------+
permissions
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| code | varchar(20) | YES | UNI | NULL | |
| description | varchar(100) | NO | | NULL | |
| createdAt | datetime | YES | | NULL | |
| updatedAt | datetime | YES | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
A client_staff has many staff_permissions, which belongs to permission.
Using the framework, I wanna to fetch the staff_permissions along with the client_staff, so this is how I tried configured the relations in ClientStaff:
return [
'client' => [self::BELONGS_TO, User::class, 'clientId'],
'staffPermission' => [self::HAS_MANY, StaffPermission::class, 'id'],
]
in StaffPermission:
return [
'staff' => [self::BELONGS_TO, ClientStaff::class, 'staffId'],
'permissions' => [self::HAS_MANY, Permission::class, 'permissionId'],
]
and in Permission:
return [
'staffPermissions' => [self::BELONGS_TO, StaffPermission::class, 'id'],
]
We have a toAPICopy method to bring the data to the client in JSON, and in this method, for classes BELONGS_TO, we make use of each classes' toAPICopy within the returned array. Below's the case of ClientStaff
public function toAPICopy()
{
return [
'id' => $this->id,
'client' => $this->client->toAPICopy(),
...,
'staffPermission' => $this->staffPermission->toAPICopy()
];
}
But nothing happens and the application hangs. No data is fetched and no error is shown, not a single thing in api.log file to help me. I do not know what I could've done wrong.
I think you are having some issue in making relations.
these are the relations as per your table structure.
ClientStaff should be:
return [
'client' => [self::BELONGS_TO, User::class, 'clientId'],
'staffPermission' => [self::HAS_MANY, StaffPermission::class, 'staffId'],
]
in StaffPermission should be:
return [
'staff' => [self::BELONGS_TO, ClientStaff::class, 'staffId'],
'permissions' => [self::BELONGS_TO, Permission::class, 'permissionId'],
]
and in Permission should be:
return [
'staffPermissions' => [self::BELONGS_TO, StaffPermission::class, 'permissionId'],
]
So, HAS_MANY will return an array of objects, therefore, you cannot call a method directly on it. The solution that worked for me is:
public function toAPICopy() {
foreach ($this->staffPermissions as $p) {
array_push($permissions, $p->toAPICopy();
}
return [ ... 'staffPermissions' => $permissions, ... ];
}

Manytomany relation in Laravel

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

Categories