I have this kind of database design
user_classes
- id
- user_id
- class_schedule_id
class_schedules
- id
- class_id
- date
classes
- id
- name
I am now in my UserClass.php Model File
public function classSchedule() {
return $this->belongsTo('\App\ClassSchedule');
}
public static function getClassByUser($user_id){
$user_class = self::where('user_id','=',$user_id)->with('classSchedule');
//other codes here...
}
My question here is that how can I access the name of the class in the class table since the user_classes table doesn't have a direct access to the class instead it should go through first to the class_schedules table.
I am not sure what Eloquent ORM Relationship should I use.
Your help will be greatly appreciated!
thanks! :)
First of all you will need to rename the third class, from class to something else. Then try this,
class user_classes Extends Eloquent {
function classSchedule() {
return $this->hasMany('Class_schedules','class_schedule_id');
}
}
class class_schedules Extends Eloquent {
function userClasses() {
return $this->belongsTo('user_classes', 'class_schedule_id');
}
function classSomething() {
return $this->hasOne('class_something','id');
}
}
class class_something Extends Eloquent {
function classSchedules() {
return $this->belongsTo('class_schedules', 'id');
}
}
Try and follow the naming conventions within Laravel, that will make your life easier down the road.
It uses the snake_cased version of the plural of your model name to define the table name automagically.
Besides that, when you have a relation with single or plural output, name your relation methods accordingly to describe what they do and what kind of output you can expect.
I prefer a dir /app/Models for the models, hence the namespace, you can change this to /app if that's where your models are.
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UserClass extends Model
{
// only defined because laravel auto generates alphabetically
protected $table = 'user_classes';
public function user()
{
// given that User model was moved to app/Models, if not, use \App\User
return $this->belongsTo('\App\Models\User');
}
public function classSchedule()
{
return $this->belongsTo('\App\Models\ClassSchedule');
}
}
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ClassSchedule extends Model
{
public function class()
{
return $this->belongsTo('\App\Models\Class');
}
}
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Class extends Model
{
public function classSchedules()
{
return $this->hasMany('\App\Models\ClassSchedule');
}
}
Now you can basically fetch all entries of UserClass for a particular user, with or without eager loading...
$userClasses = UserClass::where('user_id', $userId)->get();
$userClasses->map(function($userClass) {
echo $userClass->classSchedule->class;
});
More preferably you'll have a method userClasses() with a hasMany relation in your user model
Related
I have two models with One-to-Many relationship. I want to display data with relationship in blade.
Products Table
Table name = Products
PrimaryKey = pro_id
ForeignKey = cat_id
Categories Table
Table name = categories
PrimaryKey = cat_id
Products Model Code
namespace App;
use Illuminate\Database\Eloquent\Model;
class productsModel extends Model
{
//code...
protected $table = 'products';
protected $primaryKey = 'pro_id';
// Every Products Belongs To One Category
public function category()
{
# code...
return $this->belongsTo('APP\abcModel','cat_id');
}
}
Categories Model Code
namespace App;
use Illuminate\Database\Eloquent\Model;
class categoryModel extends Model
{
//code...
protected $table = 'categories';
protected $primaryKey = 'cat_id';
// One Category Has Many Products
public function products()
{
# code...
return $this->hasMany('App\productsModel','cat_id','pro_id');
}
}
Controller Code
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\productsModel;
class productsController extends Controller
{
//code...
public function products($category_id='')
{
# code...
$data["products"] = productsModel::where
('cat_id',$category_id)
->get();
$data["categories"] = productsModel::where
('cat_id',$category_id)->first()->category;
echo "<pre>";
print_r($data);
echo "</pre>";
}
}
ERROR:
Symfony\Component\Debug\Exception\FatalThrowableError
Class 'APP\categoryModel' not found
Seems that sometimes you have App, sometimes APP, while PHP is not case sensitive on class names, you might use an operating system (Linux?) that is case sensitive in terms of file names.
I would recommend to have only App everywhere, your error message clearly indicates: APP.
You can clearly see in your model files the namespace is written as "namespace App;"
There you defined the namespace for the app folder. So when you are using this model anywhere, you need to write it as you have defined the namespace. Therefore "App\categoryModel".
Your code should be as follows:
public function category()
{
# code...
return $this->belongsTo('App\categoryModel','cat_id');
}
Also a sincere request, as #alithedeveloper mentioned please follow PSR standards for writing code.
public function category()
{
return $this->belongsTo(abcModel::class,'cat_id');
}
public function products()
{
return $this->hasMany(productsModel::class,'cat_id');
}
I am pretty new in Laravel and need write a simple backend API.
I am doing smething wrong and I dont know what, because I get some of data from Suppliers table and empty array payments:[ ].
I am trying to get all data from two related tables - PAYMENTS and SUPPLIERS.
It`s a one to many relation SUPPLIERS_ID in PAYMENTS table is connected with ID in SUPPLIERS. Here I give You a graphic representation:
Here`s my code:
Suppliers.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany('App\Payments');
}
}
Payments.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->hasOne('App\Suppliers');
}
}
PaymentsController.php
use App\Payments;
use App\Suppliers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class PaymentsController extends Controller
{
public function index()
{
$payments = Suppliers::with('payments')->get();
return response($payments, Response::HTTP_OK);
}
}
And i get the following answear:
[{"id":1,"name":"Ekonaft","adress":"33-100 Tarnow ","email":"ekonaft#gmail.com","payments":[]},
{"id":2,"name":"Orlen","adress":"Ares testowy","email":"email#email.pl","payments":[]}]
What I`m doing wrong that I get te empty array payments:[ ] on the end of each object?
Try the inverse relationship on payments
belongsTo = has a foreign key to another table
Quoting an example
Should i use belongsTo or hasOne in Laravel?
This is how you can access suppliers from Payments
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->belongsTo('App\Suppliers');
}
}
This is payments from suppliers
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany('App\Payments','suppliers_ID','id');
}
}
Also, make sure the id's are visible on the output (if id's are hidden, laravel can't work with the relationship). You can also specify the keys on the relationship if you want to use hasOne
Edit: add the keys names within the relation, your fk naming is in capslock
Change you relations like bel
Suppliers.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Suppliers extends Model
{
public function payments()
{
return $this->hasMany(App\Payments::class, 'suppliers_ID', 'id');
}
}
Payments.php model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payments extends Model
{
public function suppliers()
{
return $this->belongsTo(App\Suppliers::class, 'suppliers_ID', 'id');
}
}
then try again..... :)
You are getting empty array of payments:[] due to miss-matching table relationship key name.
Please, make few changes in both relational function.
public function payments()
{
//return $this->hasMany('App\Model', 'foreign_key', 'local_key');
return $this->hasMany('App\Payments', 'suppliers_id');
}
public function suppliers()
{
//return $this->belongsTo('App\Model', 'foreign_key', 'other_key');
return $this->belongsTo('App\Suppliers', 'suppliers_id');
}
You can learn more about eloquent relationship directly from Laravel documentation for better understanding. https://laravel.com/docs/5.7/eloquent-relationships#one-to-many
Let me know if you still getting same error.
I have the following classes (simplified here) in my Laravel 5.7 model:
VEHICLE.PHP
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Vehicle extends Model
{
public function journeys()
{
return $this->hasMany('App\Journey');
}
}
JOURNEY PHP
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Journey extends Model
{
public function vehicle()
{
return $this->belongsTo('App\Vehicle');
}
public function users()
{
return $this->belongsToMany('App\User');
}
}
USER.PHP
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function journeys()
{
return $this->belongsToMany('App\Journey');
}
}
I have an intermediate table (journey_user) between users and journeys (see schema attached).
I can easily get all journeys made by a particular user. But how can I get all vehicles used by a particular user? The standard hasManyThrough method does not appear to work because of the Many to Many relationship between users and journeys.
Thanks for your help!
I haven't tested this out. However, it should be possible to get all vehicles by looping through all the user's journeys, creating an array of vehicles and return this as a collection.
This can be added to your User.php model controller:
/**
* Get all vehicles which user has used
*
*/
public function vehicles()
{
$vehicles = [];
$this->journeys()
->each(function ($journey, $key) use (&$vehicles) {
$vehicles[] = $journey->vehicle;
});
return collect($vehicles);
}
Here, we create an empty array. Then we loop through all the journeys of the users (passing the $vehicles array as a reference to update it).
We use the each() collection method to loop through each journey. We create a new entry to the $vehicles array, adding the vehicle.
Finally, we return all vehicles as a collection.
We can use this in our application like so:
User::find($id)->vehicles();
Note: You could return this as an accessor attribute by changing the function name to setVehiclesAttribute(). This will allow you to access the vehicle field like User::find($id)->vehicle.
In Laravel 5.6 I'm trying to load data into the user object, so I can view user credentials/settings etc.
Whats annoying is I had it working, but for some reason now It seems to have stopped, and I'm not sure what I've changed to break it.
Anyway I want to load two tables, access and settings. Both of them have user_id field in there with the corresponding user_id in.
In my User.php class I have two functions:
public function access() {
return $this->hasMany(Access::class);
}
public function settings() {
return $this->hasOne(Settings::class);
}
I am not Use-ing them at the top of the class (i.e. use \App\Access) if that makes any difference.
And then the Access class looks like:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Access extends Model
{
protected $table = "access";
}
And the Settings class is very much the same:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Settings extends Model
{
protected $table = "settings";
}
However whenever I try and access Auth::user()->settings or Auth::user()->access I get undefined index: error. It's frustrating because like I said I had it working the other day and I'm not sure what's changed.
Few things you could try here. First, Lazy Eager Load the relationships by loadMissing:
// settings
Auth::user()->loadMissing('settings');
// access
Auth::user()->loadMissing('access');
To load a relationship only when it has not already been loaded, use the loadMissing method
Second, you can use with when querying for a user, although it's not as relevant with using the auth facade:
User::with(['settings', 'access'])->where('atribute', $value)->get();
Last, if you always want the settings and access relationships to always be returned with each user model, set the with attribute on the user model:
public class User {
protected $with = ['settings', 'access'];
...
}
I usually define the inverse relationships on models as well, so Access and Settings would have a BelongsTo relationship defined:
class Access extends Model
{
protected $table = "access";
public function user() {
return $this->belongsTo(User::class);
}
}
class Settings extends Model
{
protected $table = "settings";
public function user() {
return $this->belongsTo(User::class);
}
}
I would like to make sure that I correctly used model events listeners in Laravel 5 and I didn't messed up nothing (listener vs handler?). My solution works fine, but I wonder if I developed according to concept and convention of Laravel 5.
Goal:
Always set $issue->status_id on some value when model is saving.
In app\Providers\EventServiceProvider.php
<?php namespace App\Providers;
...
class EventServiceProvider extends ServiceProvider {
...
public function boot(DispatcherContract $events)
{
parent::boot($events);
Issue::saving('App\Handlers\Events\SetIssueStatus');
}
}
In app\Handlers\Events\SetIssueStatus.php
<?php namespace App\Handlers\Events;
...
class SetIssueStatus {
...
public function handle(Issue $issue)
{
if (something)
{
$issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
}
else
{
$issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
}
// issue_status() is One-to-One relations with IssueType (belongsTo)
$issue->issue_status()->associate($issueStatus);
}
}
Thank you for your time.
As you said you have a working version and it's a valid one, now that's up to you to figure out if it's ok for you.
Just to clarify I'm not saying that these are better solutions, they are just a valid different way.
Since what you are doing is specific to the Issue model or at least it doesn't seem to be a generic event, you could set it up on your model directly
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use IssueStatus;
class Issue extends Model {
protected static function boot()
{
parent::boot();
static::saving(function($issue){
if (something)
{
$issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
}
else
{
$issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
}
// issue_status() is One-to-One relations with IssueType (belongsTo)
$issue->issue_status()->associate($issueStatus);
});
}
}
but if your event is indeed a generic one and you want to use it across multiple Models, you could achieve the same thing. You just need to extract the code from the model and use traits (like you do with soft deletes)
First we create our trait(in this case we created on the root of our App) and extract the code, I wrote before, from the model:
<?php namespace App
use IssueStatus;
trait IssueStatusSetter
{
protected static function boot()
{
parent::boot();
static::saving(function($model){
if (something)
{
$issueStatus = IssueStatus::where(somethingElse)->firstOrFail();
}
else
{
$issueStatus = IssueStatus::where(somethingAnother)->firstOrFail();
}
// issue_status() is One-to-One relations with IssueType (belongsTo)
$model->issue_status()->associate($issueStatus);
});
}
}
Now on the models where you want to use it, you just import the trait and declare it's use:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use IssueStatusSetter;
class Issue extends Model {
use IssueStatusSetter;
}
Now this last option I showed you it's a generic option you have that you could apply to every Model by just declaring it's use on the top of your model.