I want to use another model for cashier, not the default. I have 2 tables User and Hotel relation one-to-many (a user can have multiple hotels). I want to add possibility that a user can add different payment methods for his hotels. I removed cashier columns from user and I added to hotel table.
I put in services.php :
'stripe' => [
'model' => \App\Models\Hotel::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
In my controller :
public function get(Request $request)
{
$creditorId = config('id');
$user = $request->user();
$stripeUser = $user->createOrGetStripeCustomer();
.............
}
I added in Hotel.php Billable and I removed Billable from User.
Now I have the error :
Call to undefined method App\Models\User::createOrGetStripeCustomer()
In the past was working for User.php. How can I fix this error?
User.php :
class User extends Authenticatable implements CanResetPassword {
use Notifiable, HasSanctumTokens, HasFactory;
protected $fillable = [
'email',
'password',
'lang',
];
.......
Hotel.php :
class Hotel extends Model
{
use Billable, HasFactory;
public $incrementing = false;
protected $fillable = [
'id',
'name',
'user_id',
];
.............
This error appears because you remove the Billable trait from your User model and moved it to the Hotel model
so what do you need to do from the model relation in this case (one -> many)
User Model
class User extends Authenticatable implements CanResetPassword {
use Notifiable, HasSanctumTokens, HasFactory;
protected $fillable = [
'email',
'password',
'lang',
];
public function hotels()
{
return $this->hasMany(Hotel::class);
}
after that from the controller you need to pass the hotel as a parameter instead of user
Controller
public function get(Request $request, Hotel $hotel)
{
$stripeUser = $hotel->createOrGetStripeCustomer();
.............
}
Related
I have 4 MySQL tables, using PHP and Laravel 7
members
deductions
payments
payment_deductions
Now I want to display every single member in a row with his/her single payment and all other deductions. (Assuming One person has only one payment)
The DB schema is as follows
and here is the HTML table I want to display
Here is the query I'm using but it duplicates the data.
$payments = Payment::leftJoin('members', 'payments.member_id', '=', 'members.id')
->leftJoin('payment_deductions', 'payments.id', '=', 'payment_deductions.payment_id')
->leftJoin('deductions', 'payment_deductions.deduction_id', '=', 'deductions.id')
->select(
'members.*',
'payment_deductions.*',
)
->orderBy("member_id", "ASC")
->get()->toArray();
The resulting array repeats every member as per their deductions.
Is there any way to get this data better? Something like a nested array of deductions with each member?
Here are the models
Member
namespace App;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Member extends Model
{
protected $fillable = [
'full_name',
'email',
'created_by',
];
}
Payment
namespace App;
use Illuminate\Database\Eloquent\Model;
class Payment extends Model
{
protected $fillable = [
'member_id',
'total_amount',
'payable_amount',
'created_by',
];
public function deductions() {
return $this->belongsToMany(Deduction::class,'payment_deductions')->withTimestamps();
}
}
Deduction
namespace App;
use Illuminate\Database\Eloquent\Model;
class Deduction extends Model
{
protected $fillable = [
'title',
'priority',
'created_by',
];
}
You were very close and on the right track when structuring models, what you were missing is how to load the relationships without creating another query, if you take a look at the controller you will see the standard way to load inner relationships. Hopefully this serves as a better concept to tackle your concerns.
For reference: https://laravel.com/docs/9.x/eloquent-relationships#lazy-eager-loading
Also doing it this way will avoid future N+1 issues see What is the "N+1 selects problem" in ORM (Object-Relational Mapping)? for details on N+1
Member Model
public class Member extends Model
{
protected $fillable = [
'full_name',
'email',
'created_by',
];
public function payments(){
return $this->hasMany(Payment::class);
}
}
Payment Model
public class Payment extends Model
{
protected $fillable = [
'member_id',
'total_amount',
'payable_amount',
'created_by',
];
public function member(){
return $this->belongsTo(Member::class);
}
public function deductions() {
return $this->belongsToMany(Deduction::class,'payment_deductions')->withTimestamps();
}
}
Deduction Model
public class Deduction extends Model
{
protected $fillable = [
'title',
'priority',
'created_by',
];
public function payments() {
return $this->belongsToMany(Payment::class,'payment_deductions')->withTimestamps();
}
}
MemberController:
/**
* Show the specified model.
*
* #param \Illuminate\Http\Request $request
* #param Member $member
* #return \Illuminate\Http\Response
*/
public function show(Request $request, Member $member){
// This will load all of the inner relationships in a single query.
$member->load('payments.deductions');
//Assign the loaded payments to be used
$payments = $member->payments;
/*
You can acess the payments -> deductions in a foreach loop, in php or blade
foreach($payments->deductions as $deduction){
//$deduction->id
}
*/
return view('sampleView', compact('member', 'payments'));
}
I have three Eloquent models for a recipe management application where User has many cookbook, cookbook has many recipes and so on (see below).
To authorize I'm using this policy:
public function view(User $user, Recipes $recipe) {
return $user->id === $recipe->cookbook->user_id;
}
Here is the controller:
public function show($id) {
$recipe = Recipes::find($id);
$this->authorize('view', $recipe);
return $recipe;
}
Testing this works fine, however I'm getting extra information in my response.
The response somehow gets assigned an extra object cookbook. After print testing the problem seems to lie on the line $recipe->cookbook->user_id; where if removed the result came to be as expected.
Am I overlooking something?
Models for Reference
User
class User extends Authenticatable
{
use HasFactory, Notifiable, HasApiTokens;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function cookbooks() {
return $this->hasMany('App\Models\Cookbook');
}
public function recipes() {
return $this->hasManyThrough('App\Models\Recipes', 'App\Models\Cookbook');
}
}
Cookbook
class Cookbook extends Model
{
use HasFactory;
protected $guarded = ['user_id'];
protected $fillable = [
'cookbook_name',
];
protected $casts = [
'cookbook_shared_user' => 'string'
];
public function user() {
return $this->belongsTo('App\Models\User');
}
public function recipes() {
return $this->hasMany('App\Models\Recipes');
}
}
Recipe
class Recipes extends Model
{
use HasFactory;
protected $guarded = ['cookbook_id'];
protected $fillable = [
'recipe_name',
'recipe_description',
'recipe_video_url',
'recipe_image_url'
];
public function cookbook() {
return $this->belongsTo('App\Models\Cookbook');
}
}
You're loading the relationship in your policy, exactly where you said:
$recipe->cookbook
Now in your controller, you can change your return to:
return $recipe->setAppends([]);
That will remove your appends like cookbook.
If you want more control you can use API Resources (Laravel way).
I am doing a learning project. very new to Laravel. So I have a User and a Company profile CRUD. Company belongsTo User and User may have many Company. So in my User model I implemented this
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Company;
class User extends Authenticatable
{
use Notifiable;
protected $fillable = [
'first_name', 'last_name', 'username', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
//relation with company
public function company(){
return $this->hasMany('App\Company','id');
}
}
and in company model i did
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
//table name
protected $table='companies';
//primary keys
protected $primaryKey='id';
//relation with User Model
public function user(){
return $this->belongsTo(App\Models\User::class);
}
My company profile controller is
public function index()
{
//Showing companies under user
$user_id = auth()->user()->id;
$user = User::find($user_id);
$companies=$user->company;
return view('company.profile')->with('companies', $companies);
}
But when it comes to execution, it seems like
public function user(){
return $this->belongsTo(App\Models\User::class);
}
this function in Company model is not working. I mean a company is getting assigned to one user but it should be like many companies in one user. What did I do wrong?
Btw my User model location is App/Model/User.php, and I declared the user model path in auth.php .My Company.php Model location is App/Company.php. please have a look and try to help this newb out. Many thanks.
i don't understand your question but my answer may be help you
users belongs to company
in model user
public function company()
{
return $this->belongsTo('App\Company');
}
maby be wrong code
//relation with company
public function company(){
return $this->hasMany('App\Company','id'); // not Id foreign_key as company_id
}
this is true but you can write it better as
public function index()
{
$user_id = auth()->user()->id;
$user = User::find($user_id)->with('company');
//$companies=$user->company;
return view('company.profile', compact('user');
}
i have two tables:
**plans:**
planId, plan_name
**Users:**
userId, user_name, password, planId
i tried to get the name of the plan where i select all users.
this is the users model:
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Users extends Authenticatable {
public $timestamps = false;
protected $table = 'users';
protected $primaryKey = 'userId';
protected $fillable = [
'user_name',
'password',
];
protected $hidden = [
'_token',
];
public function plan()
{
return $this->belongsTo('App\Plans', 'planId');
}
public function validateCredentials( MyUserInterface $user, array $credentials ) {
$plain = $credentials["password"] . $user->getAuthPasswordSalt();
return $this->hasher->check( $plain, $user->getAuthPassword() );
}
}
and this is the plan model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Plans extends Model {
public $timestamps = false;
protected $table = 'plans';
protected $primaryKey = 'planId';
protected $fillable = [
'plan_name'
];
protected $hidden = [
'_token',
];
public function users()
{
return $this->hasMany('App\Users', 'planId');
}
}
when i used:
\App\Users::get();
there is no relations in the output... there is only the users.
what can i do?
i tried to used hasOne and the same issue...
tnx a lot
You can eager load the relationships like this:
\App\Users::with('plan')->get();
Or add a $with property to always eager load it when you fetch an user:
class Users extends Authenticatable
{
protected $with = [
'plan'
];
}
If you don't want to eager load it, you can access the plan of each user's instance like this:
$users = \App\Users::get();
foreach ($users as $user) {
dd($user->plan);
}
Am using Zizaco entrust package and trying to get all users together with their roles
User model i have
use Laravel\Passport\HasApiTokens;
use Illuminate\Database\Eloquent\Model;
use Zizaco\Entrust\Traits\EntrustUserTrait;
class User extends Model implements AuthenticatableContract
{
use Authenticatable,HasApiTokens, EntrustUserTrait;
protected $fillable = [
'name', 'email', 'password','status'
];
protected $hidden = [
'password', 'remember_token',
];
public function role()
{
return $this->belongsTo('App\Role', 'id');
}
}
Now the App\Role
use Zizaco\Entrust\EntrustRole;
class Role extends EntrustRole
{
}
Whenver i fetch my users with
$sortval = explode("|",$request->sort);
return \App\User::orderBy( $sortval[0], $sortval[1])
->with("role") //added the relationship
->paginate($request->per_page);
The above role always returns null even when there are assigned roles to users.