How use conditional relationship in eloquent laravel - laravel

I have a 'conversation_message' table and separate sender role by column 'sender_type' (admin/user). Both of admin & user in a different table. But when I call the model, that showed error Call to a member function addEagerConstraints() on null
Table column and data
| id | id_group | id_reply | id_sender | sender_type | message
| 1 | 1 | null | 3 | admin | Hi, I'm admin
| 2 | 1 | 1 | 3 | admin | I wanna give u promo
| 3 | 1 | 2 | 18 | user | What's promo ?
I've tried if conditional with column value, but it doesn't work.
Conversation_message.php
public function sender(){
switch($this->sender_type){
case "user":
return $this->belongsTo(User::class, 'id_sender', 'id');
case "admin":
return $this->belongsTo(Admin::class, 'id_sender', 'id');
default:
return;
}
}
InboxController.php
public function message_detail_chat($groupId){
$data = [];
$data['messages'] = Conversation_message::with('replies')
->with('sender')
->with('recipients')
->where(['id_group' => $groupId])->get();
}
I expect to use conditional model by column value 'sender_type' but the actual output is wrong.

laravel provide query scope your can read it from here https://laravel.com/docs/5.8/eloquent#local-scopes
function userSender(){
$this->belongsTo(User::class, 'id_sender', 'id');
}
function adminSender(){
return $this->belongsTo(Admin::class, 'id_sender', 'id');
}
public function scopeSender($query)
{
return $query
->when($this->sender_type === 'user',function($q){
return $q->with('userSender');
})
->when($this->sender_type === 'admin',function($q){
return $q->with('adminSender');
});
}
Now you can access your Sender like this
Conversation_message::Sender()->first();
This should give you the right Sender. Hope it helps.

Related

Laravel model observer method doesn't get fired

In my Laravel (7.x) I am trying to use Observers for updating device_inventories table if the value of the record if the record of the subscriber_devices table is updated as inactive.
device_inventories | subscriber_devices
----------------------- | --------------------------------
# | title | status | # | device_inventory_id | status
----------------------- | --------------------------------
1 | device-1 | active | 1 | 1 | active
2 | device-2 | active | 2 | 2 | active
For example:
Suppose I update the record id = 2 of subscriber_devices to status = inactive then the value of device_inventories / status should be updated to replacement. Assuming, that the device was damaged and needs to be sent for replacement.
AppServiceProvider.php
use App\SubscriberDevice;
use App\Observers\ObserverChangeDeviceInventoryStatusToReplacement;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
SubscriberDevice::observe(ObserverChangeDeviceInventoryStatusToReplacement::class);
}
}
App\Observers\ObserverChangeDeviceInventoryStatusToReplacement.php
use App\DeviceInventory;
use App\SubscriberDevice;
class ObserverChangeDeviceInventoryStatusToReplacement
{
public function updated(SubscriberDevice $SubscriberDevice)
{
DeviceInventory::where('id', $SubscriberDevice->device_inventory_id)->update([
'status' => 'replacement'
]);
}
}
App\SubscriberDevice.php
class SubscriberDevice extends Model
{
protected $table = 'subscriber_devices';
public function _status($token, $reason)
{
self::where('token', $token)->update([
'reason' => $reason,
'status' => 'inactive',
]);
}
}
The observer method doesn't seems to be firing. What am I doing wrong.?
Thanks to #EmptyBrain.
App\SubscriberDevice.php
class SubscriberDevice extends Model
{
protected $table = 'subscriber_devices';
public function _status($token, $reason)
{
$self = self::where('token', $token)->first();
$self->update([
'reason' => $reason,
'status' => 'inactive',
]);
}
}
Reference laravel Eloquent model update event is not fired

Laravel eloquent get count on belongsTo id

I have 2 tables subscribers & subscriber_packages. I need to fetch the count of currently active packages for the selected subscriber via given subscriber_package / id.
Tables:
# | subscriber_id | package_id | active
---------------------------------------
1 | 1 | 1 | true
2 | 1 | 2 | true
3 | 1 | 3 | true
4 | 1 | 4 | false
---------------------------------------
App\SubscriberPackage.php
class SubscriberPackage extends Model
{
public function subscriber()
{
return $this->belongsTo(Subscriber::class);
}
public function package()
{
return $this->belongsTo(Package::class);
}
public function _countActivePackages($subscriberPackage)
{
return self::where([
'id' => $subscriberPackage,
'status' => \Common::STATUS_ACTIVE,
])->whereHas('subscriber')->count();
}
}
At your subscriber you need to define correctly a HasManyThrough relationship and just add properly a where cause to check the status even in separate method
public function packages()
{
return $this->hasManyThrough(Package::class, SubscriberPackage::class);
}
public function activePackages()
{
return $this->packages()
->where("subscriber_package.status", "=", "active");
}
After that you can always make a count with it
$subscriber->activePackages()->count();

Laravel miltiple level relationship with limit()

I have some problem with Laravel Eloquent and need your help.
I want to display 1 replies of each comment of single post.
Here is my tables
posts (id,title)
id | title
---------------------
1 | My post
---------------------
comments(id,post_id,comment,parent_id)
id | post_id | comment | parent_id
-----------------------------------------
1 | 1 | First comment | null
-----------------------------------------
2 | 1 | Second comment | null
-----------------------------------------
3 | null | 3rd comment | 1
-----------------------------------------
4 | null | 4th comment | 1
-----------------------------------------
5 | null | 5th comment | 2
-----------------------------------------
6 | null | 6th comment | 2
-----------------------------------------
My model (Eloquent)
class Post extends Model
{
public function comments()
{
return $this->hasMany('Comment', 'post_id');
}
}
---------------------
class Comment extends Model
{
public function reply()
{
return $this->hasMany('Comment', 'parent_id');//self relationship
}
}
My query function
public function getPost($postId){
$posts = Post::with(['comment.reply'=>function($q){
$q->limit(1);
}])
->find($postId);
return $posts;
}
And I get result
{[
id=>1,
title=>'My post',
'comments'=>[
0=>[
id=>1,
comment=>'First comment',
parent_id=>null,
post_id=>1,
reply=>[
0=>[........(comment id:3).......]
]
],
1=>[
id=>2,
comment=>'Second comment',
parent_id=>null,
post_id=>1,
reply=>null
]
]
]}
But I want like this
{[
id=>1,
title=>'My post',
'comments'=>[
0=>[
id=>1,
comment=>'First comment',
parent_id=>null,
post_id=>1,
reply=>[
0=>[........(comment id:3,4)........]
]
],
1=>[
id=>2,
comment=>'Second comment',
parent_id=>null,
post_id=>1,
reply=>[
0=>[........(comment id: 5,6).........]
]
]
]
]}
Please kindly help!
Try this:
$posts=Post::where(['id'=>1])->with(['comments'=>function($query)
{
$query->with(['replies'=>function($query)
{
$query->limit(1);
}]);
}])->first();
print_r($posts);

Share value from database in all view in laravel 5

I'm new to laravel. I'm trying to create a simple app with some variable that shouold be in every view. So I create a setting model, with many fields and a unique slug field. Now to share this variable from database I've created a middleware:
public function handle($request, Closure $next)
{
$site_settings = Cache::remember('settings', 60, function() {
return Setting::all();
});
view()->share('site_settings', $site_settings);
return $next($request);
}
Now to show this variable in view I have:
{{{ $site_settings->get(0)->value }}}
This works great, but I'd like to have a more intuitive code in my view, accessing the setting by slug. Something like:
{{{ $site_settings->findBySlug("MYVARIABLE")->value }}}
So it's possible to filter collection by an unique slug?
Info:
This assumes your settings table structure is as following:
----------------------
| id | key | value |
----------------------
| 1 | titleĀ | foo |
| 2 | asd | bar |
| 3 | qqq | zzz |
----------------------
Steps
Step 1: Put the following newCollection method into App\Setting model:
class Settings extends ... {
public function newCollection(array $models = array())
{
return new \App\Collections\SettingsCollection($models);
}
}
Step 2: Put the following lines into App\Collections\SettingsCollection class:
<?php namespace App\Collections;
use Illuminate\Database\Eloquent\Collection;
class SettingsCollection extends Collection {
public function get($name, $default = null)
{
return array_first($this->items, function($itemKey, $model) use ($name)
{
return $model->key == $name;
}, $default)->value;
}
}
Step 3: Enjoy! This is the collection I'm currently using. Instead of this:
$settings = Setting::all();
$settings->where('key', 'key_name')->first()->value;
You can simply just do this:
$settings = Setting::all();
echo $settings->get('key_name'); // returns value of the setting with the key 'title'
Maybe a query scope would fit.
In your model:
public function scopeFindBySlug($slug){
return $query->where('slug','=', $slug);
}
So you will have: $site_settings->findBySlug('your_slug')->get();

Adding methods to resource routes

I'm trying to add methods to my resource routes that have a parameter. If I create one without a parameter it works find, but when I try to add a parameter it doesn't work.
Here's the code
Route::get('temp_user/activate/{id}', 'TempUserController#activate');
Route::resource('temp_user','TempUserController', array('only' => array('index','create','store')));
The above code doesn't work, but I need to pass a parameter to my method. Please help.
Works fine here. To not create a new controller I just used and old one:
<?php
class StoreController extends Controller {
public function activate($id)
{
return 'activate '.$id;
}
public function index()
{
return 'index';
}
public function create()
{
return 'create';
}
}
Using routes:
Route::get('temp_user/activate/{id}', 'StoreController#activate');
Route::resource('temp_user','StoreController', array('only' => array('index','create','store')));
After executing
php artisan routes
I get
| | GET /temp_user/activate/{id} | | StoreController#activate | | |
| | GET /temp_user | temp_user.index | StoreController#index | | |
| | GET /temp_user/create | temp_user.create | StoreController#create | | |
| | POST /temp_user | temp_user.store | StoreController#store | | |
And browsing:
http://172.17.0.2/temp_user/create
http://172.17.0.2/temp_user/activate/1
http://172.17.0.2/temp_user
Everything works fine.

Resources