Insert into DB based on a Join -> Laravel - laravel

I am working on a roll format for a laravel project.
I have successfully created the roll, and can update the roll status in the roll table which looks like this
|id|roll_id|member_id|status|created_at|updated_at|
One of my status is "Present/Voucher" using funds off a Voucher
I have the Voucher Table
|id|member_id|voucher|date|balance|created_at|updated_at|
When a user clicks on the present/voucher icon in the roll, the following is called in the controller
public function voucher($id)
{
$r = Roll::find($id);
if ($r != null)
{
$r->status = "V";
$r->save();
return redirect(action('RollController#index'))->with ('success', 'Member Paid with Vocuher');
}
return redirect(action('RollController#index'));
}
This works perfect, what I would like to know is how to insert a record into my Voucher table, while I can find the id record in the roll table, I need to pull that member_id so I can add this into the voucher table
For example if the Roll Record looks like this
|id|roll_id|member_id|Status|
|20|2|13|V|
I need to grab 13 are the Member_ID from roll record 20, so I can insert in the vouchers table
|id|member_id|voucher|date|balance
|2|13|Weekly Fees|currdate|-10
Please note the 10 is also stored in a settings table, so if I can grab from that table that would be great
Settings Table:
|id|Setting|Value|
|1|weekly Subs|10|
Thanks

You could first define model relationship.
Member
class Member extends Model {
public function vouchers()
{
return $this->hasMany('App\Voucher');
}
}
Roll
class Roll extends Model {
public function member()
{
return $this->belongsTo('App\Member');
}
}
Voucher
class Voucher extends Model {
public function member()
{
return $this->belongsTo('App\Member');
}
public function setting()
{
return $this->belongsTo('App\Setting');
}
}
Then you can execute fluently in controller, you should also use lockForUpdate and DB::transaction
public function voucher($id)
{
DB::transaction(function () use ($id) {
$roll = Roll::lockForUpdate()->find($id);
if ($roll != null) {
$roll->status = "V";
$roll->save();
$voucher = new Voucher();
$voucher->member_id = $roll->member_id;
...
// Correct me if I am wrong, form your table structure it looks like you linked table voucher and setting with 'value'
// I strongly recommend you to have setting_id as foreign key in table voucher
// So you could do
// $setting = Setting::where('Setting', 'weekly Subs')->where('Value', 10)->first();
// $voucher->setting_id = $setting->id;
$voucher->save();
return redirect(action('RollController#index'))->with ('success', 'Member Paid with Vocuher');
}
}
return redirect(action('RollController#index'));
}

Related

How can I access model Relation with where condition of child and parent table in laravel?

I have Games table and which has the following schema
id | status | name
status column has 2 values (Active, Pending)
And GamePlayer table which has the following schema
id | game_id | player_id | request_status
request_status column has 3 values (Pending, Confirm, Rejected)
Now I have to select all game in which the player is involved but with the following constraints:
If the game is Pending state then it will be shown to all game_players
If the game is in Active state then it will be only shown to the game_player whose request_status is Confirm.
Game(Model)
public function GamePlayer()
{
return $this->hasMany('App\Models\GamePlayer', 'game_id', 'id');
}
public function getGames($playerId)
{
$gameList = Game::with(['GamePlayer','Category:id,name'])
->whereHas('GamePlayer', function ($q) use ($playerId) {
$q->where('player_id', $playerId);
})->get();
return $gameList;
}
Controller
$this->gameObj = new Game();
$gameList = $this->gameObj->getGames($player_id);
Please help me out how can I populate data from another table based on condition(parent table as well as the child).
You can use condition in your relationship to get only confirmed game players
public function activeGamePlayers()
{
return $this->hasMany('App\Models\GamePlayer', 'game_id', 'id')
->where('request_status', 'confirm');
}
You can as well use scopes (https://laravel.com/docs/7.x/eloquent#local-scopes) to select only active games
public function scopeActive($query)
{
return $query->where('status', 'active');
// You can then use $game->active()->...
}
So your getGame would look like:
public function getGames($playerId)
{
$player = GamePlayer::find($playerId);
if ($player->status == 'active') {
$gameList = Game::with(['GamePlayer', 'Category:id,name'])
->get();
} else {
$gameList = Game::with(['GamePlayer', 'Category:id,name'])
->active()->get();
}
return $gameList;
}
NOTE:
in your specific case, I would instead get started from the GamePlayer Model to get the games, instead of coming from the Game Model - you can use scopes and conditions in relationships as well to make your code more readable.
You can use Laravel method whereHas. You should read this part of Laravel the documentation.
Note that you should have relationships declared on every model.

HasMany Relation through BelongsToMany Relation

Is it possible to make Laravel relation through belongsToMany relations?
I have 4 tables:
1)Restaurants (id , name) - uses hasManyRelation with Workers table
2)Directors (id , name)
3)Directors_Restaurants (id, director_id, restaurant_id) - pivot table for connecting belongsToMany Restaurants with Directors
3)Workers (id, name, restaurant_id)
With this function in Directors model i can get all connected restaurants
public function restaurants()
{
return $this->belongsToMany('App\Restaurant','director_restaurant');
}
With this function in my code i can get all workers of all restaurants of one director
$director = Director::find(1);
$director->load('restaurants.workers');
$workers = $director->restaurants->pluck('workers')->collapse();
So my question is : can i declare similar relation in my Director model to get all its workers of all its restaurants?
Of course you can have hasMany relationship method on Director model with Eager Loading
just like below
public function restaurants()
{
return $this->hasMany(Restaurant::class)->with('restaurants.workers');
}
i can suggest a solution like this:
Director Model OPTION 1
public function getAllRestaurants(){
return $this->hasMany(Restaurant::class)->with('restaurants.workers');
}
Director Model OPTION 2
public function getAllRestaurants(){
$this->load('restaurants.workers');
return $this->restaurants->pluck('workers')->collapse();
}
You can get all restaurants anywhere
$all_restaurants = Director::find(1)->getAllRestaurants();
You can define a direct relationship by "skipping" the restaurants table:
class Director extends Model
{
public function workers()
{
return $this->belongsToMany(
Worker::class,
'director_restaurant',
'director_id', 'restaurant_id', null, 'restaurant_id'
);
}
}
You can define an accessor method in your model to hide some of the logic
# App/Director.php
// You'll need this line if you want this attribute to appear when you call toArray() or toJson()
// If not, you can comment it
protected $appends = ['workers'];
public function getWorkersAttribute()
{
return $this->restaurants->pluck('workers')->collapse();
}
# Somewhere else
$director = Director::with('restaurants.workers')->find(1);
$workers = $director->workers;
But ultimately, you still have to load the nested relationship 'restaurants.workers' for it to work.
Given your table attributes you could also define a custom HasMany relationship that looks like this
# App/DirectorRestaurant.php
public function workers()
{
return $this->hasMany(Worker::class, 'restaurant_id', 'restaurant_id');
}
# Somewhere else
$director = Director::find(1);
$workers = DirectorRestaurant::where('director_id', $director->id)->get()->each(function($q) { $q->load('workers'); });
But I don't recommend it because it's not very readable.
Lastly, there's the staudenmeir/eloquent-has-many-deep package where you can define that sort of nested relationship.
https://github.com/staudenmeir/eloquent-has-many-deep

Laravel many to many with column in pivot table

I have 3 tables:
Worker, payments and private
A private can pay one or more worker and the worker can receive payments from one or more privates.
The payments table contains the 2 foreign key and the amount.
How can I create the relations in the 3 tables with laravel to get all the informations in the db?
For example i want to have for every worker the payments he receives from every private with the amount.
This is how you define many to many relationship between Worker and Private
Worker Model
public function privates()
{
return $this->belongsToMany(Private::class, 'payments', 'worker_id', 'private_id')
->withPivot('amount');
}
Private Model
public function workers()
{
return $this->belongsToMany(Worker::class, 'payments', 'worker_id', 'private_id')
->withPivot('amount');
}
this is how you can retrieve all the privates of a worker
Controller Function
$privates = $worker->privates;
// this '$privates' contains the 'pivot' table values which contains the 'amount'.
this is how you save amount.
Controller Function
// first $private and $worker need to have saved.
// and then attach particular $worker as below.
$private->attach($worker_id, ['amount' => 1200.00]);
I'm assuming you already know laravel relationships.
Worker.php
public function privates()
{
return $this->belongsToMany('App\Private')->withPivot('amount');
}
Private.php
public function workers()
{
return $this->belongsToMany('App\Worker')->withPivot('amount');
}
then in your controller
$private = Private::create();
$worker = Worker::create();
$amount = 1000;
$private->workers()->attach($worker->id, ['amount' => '$amount']);
^^^-column in your payment table.

Laravel oneToMany accessor usage in eloquent and datatables

On my User model I have the following:
public function isOnline()
{
return $this->hasMany('App\Accounting', 'userid')->select('rtype')->latest('ts');
}
The accounting table has activity records and I'd like this to return the latest value for field 'rtype' for a userid when used.
In my controller I am doing the following:
$builder = App\User::query()
->select(...fields I want...)
->with('isOnline')
->ofType($realm);
return $datatables->eloquent($builder)
->addColumn('info', function ($user) {
return $user->isOnline;
}
})
However I don't get the value of 'rtype' for the users in the table and no errors.
It looks like you're not defining your relationship correctly. Your isOnline method creates a HasMany relation but runs the select method and then the latest method on it, which will end up returning a Builder object.
The correct approach is to only return the HasMany object from your method and it will be treated as a relation.
public function accounts()
{
return $this->hasMany('App\Accounting', 'userid');
}
Then if you want an isOnline helper method in your App\User class you can add one like this:
public function isOnline()
{
// This gives you a collection of \App\Accounting objects
$usersAccounts = $this->accounts;
// Do something with the user's accounts, e.g. grab the last "account"
$lastAccount = $usersAccounts->last();
if ($lastAccount) {
// If we found an account, return the rtype column
return $lastAccount->rtype;
}
// Return something else
return false;
}
Then in your controller you can eager load the relationship:
$users = User::with('accounts')->get(['field_one', 'field_two]);
Then you can do whatever you want with each App\User object, such as calling the isOnline method.
Edit
After some further digging, it seems to be the select on your relationship that is causing the problem. I did a similar thing in one of my own projects and found that no results were returned for my relation. Adding latest seemed to work alright though.
So you should remove the select part at very least in your relation definition. When you only want to retrieve certain fields when eager loading your relation you should be able to specify them when using with like this:
// Should bring back Accounting instances ONLY with rtype field present
User::with('accounts:rtype');
This is the case for Laravel 5.5 at least, I am not sure about previous versions. See here for more information, under the heading labelled Eager Loading Specific Columns
Thanks Jonathon
USER MODEL
public function accounting()
{
return $this->hasMany('App\Accounting', 'userid', 'userid');
}
public function isOnline()
{
$rtype = $this->accounting()
->latest('ts')
->limit(1)
->pluck('rtype')
->first();
if ($rtype == 'Alive') {
return true;
}
return false;
}
CONTROLLER
$builder = App\User::with('accounting:rtype')->ofType($filterRealm);
return $datatables->eloquent($builder)
->addColumn('info', function (App\User $user) {
/*
THIS HAS BEEN SUCCINCTLY TRIMMED TO BE AS RELEVANT AS POSSIBLE.
ARRAY IS USED AS OTHER VALUES ARE ADDED, JUST NOT SHOWN HERE
*/
$info[];
if ($user->isOnline()) {
$info[] = 'Online';
} else {
$info[] = 'Offline';
}
return implode(' ', $info);
})->make();

how to construct a function to detect if a relation is active or expired - eloquent

I have two models: Entity and Entityrelation.
The Entities can enter relationships.
I try to construct a table with lists of present and past relations
in the Entity I have this function:
// Entity.php
public function activeMembership()
{
return $this->hasOne('App\Models\Entityrelation', 'entitychild_id')->NotCeased()->Where('relationtype_id', '=', '4');
}
The NotCeased is a scope defined in the Entityrelation model:
// Entityrelation.php
public function scopeCeased($query)
{
return $query->where('ceased', 1);
}
public function scopeNotCeased($query)
{
return $query->where('ceased', 0);
}
The ceased is a column in the relationships table.
So when I want to get a number of active memberships, I just do this :
$object = Entity::find(1);
and in my view
$object->public function activeMembership()->count();
and a simple #foreach loop produces me a list of all active memberships of the Entity with id = 1.
My question
I want to design a function, which check if a given Entity was a child in an relation with an organization with ID = $parent_id (in entityparent_id).
returns 1 when an active relationship was found.
returns 0when the found relation was expired (ceased = 1)
returns null when no relation with the organization ever existed
First off, your relationship is not properly defined. You should have this in Entity.php: (relevant doc)
public function entityRelation() {
return $this->hasOne('App\Models\Entityrelation', 'entitychild_id');
}
Once you have this, you can use $entity->entityRelation to access an entity's relation.
Once you have that, it's pretty easy to do the requested function:
public function myMethod(Entity $entity, $parent_id) {
if ($entity->entityRelation && $entity->entityRelation->id === $parent_id) {
return $entity->entityRelation->ceased ? 0 : 1;
} else {
return null;
}
}

Resources