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, ... ];
}
Related
I am using laravel framework to develop web application ,i am using soft-deletes so while fetching the data from database i have to check weather the column is null or not ,for that i wrote a following query
QueryBuilder
$today= "2022-09-23 00:00:00";
$this->repository->pushCriteria(new WhereCriteria('date_of_leaving', $today));
querylog
array (
'query' => 'select * from `employees` where `date_of_leaving` = ? and `employees`.`deleted_at` is null',
'bindings' =>
array (
0 => '2022-09-23 00:00:00',
),
'time' => 2.36,
),
table structure
+-----------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | | NULL | |
| joining_date | timestamp | NO | | NULL | |
| manager_id | bigint unsigned | NO | MUL | NULL | |
| image_path | varchar(255) | YES | | NULL | |
| date_of_leaving | timestamp | YES | | NULL | |
| still_working | timestamp | YES | | NULL | |
| deleted_at | timestamp | YES | | NULL | |
+-----------------+-----------------+------+-----+---------+----------------+
data
+---------------------+---------------------+
| date_of_leaving | deleted_at |
+---------------------+---------------------+
| 2022-09-23 00:00:00 | 2022-09-23 11:47:11 |
| 2022-09-23 00:00:00 | 2022-09-23 12:36:46 |
| 2022-09-23 00:00:00 | 2022-09-23 13:09:55 |
| NULL | NULL |
| 2022-09-06 00:00:00 | NULL |
| NULL | NULL |
| NULL | NULL |
| NULL | NULL |
| NULL | 2022-09-23 11:45:01 |
| NULL | NULL |
| NULL | NULL |
+---------------------+---------------------+
Actually in database three matching records are there with the above condition but this query is not fetching the data ,i was suspecting deteled_at was considering NULL as string
Try This.
array (
'query' => 'select * from employees where date_of_leaving Is Null and employees.deleted_at is null',
'bindings' =>
array (
0 => '2022-09-23 00:00:00',
),
'time' => 2.36,
),
Try doing this, i believe the package you are using does not support Laravel's softDelete() feature.
$this->repository->pushCriteria(new WhereCriteria(['date_of_leaving',=> $today,'deleted_at'=>Null]));
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");
}
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);
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
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