I'm starting to get confused. I have an user model and an event models. A user can create an event, he is the owner. But he can also get invited to an event, he is a guest. The first relation is a OneToMany relation and the other one is a ManyToMany relation.
Now, I would like to retrive all the events of an user, owned or guest. Every events and order them by the field date.
This my user model :
class User extends Authenticatable
{
/**
* Get the events of the user.
*/
public function owned_events()
{
return $this->hasMany('App\Event', 'owner_id');
}
/**
* Get the events list.
*/
public function events()
{
return $this->belongsToMany('App\Event')
->using('App\Invitation')
->withPivot('status')
->withTimestamps();
}
}
This is the event model :
class Event extends Model
{
/**
* Get the owner of the event.
*/
public function owner()
{
return $this->belongsTo('App\User');
}
/**
* Get the guests list.
*/
public function guests()
{
return $this->belongsToMany('App\User')
->using('App\Invitation')
->withPivot('status')
->withTimestamps();
}
}
This is what I tried (inside an EventRepository)
/**
* Return all the events (owner and guest) of a user ($id).
*/
public function all($id)
{
$guested = $this->event->guests()->where('user_id', $id)->get()->load('owner', 'guests');
$own = $this->event->where('owner_id', $id)->get()->load('owner', 'guests');
return $guested->merge($own)->sortBy('date');
}
It works... but it gives me only the owned events, not where my user is the guest... I think that there is a much better way to do it. Two calls for one request is pretty bad and two loads is even worse no?
I think I found the solution :
$user = Auth::user()->load('owned_events', 'events'));
$events = $user->events->merge($user->owned_events)->sortBy('date');
return view('events.index', compact('events'));
Go throught the event model was way too hard while go throught the user model is much easier :)
Related
My users table has a field of points, and I have an Observer that tracks specifically that field. When that field is updated, a new record of TransactionPoints is created by triggering an event.
My Observer:
class UserPointObserver
{
/**
* Handle the User "saved" event.
*
* #param \App\Models\User $user
* #return void
*/
public function saved(User $user)
{
if ($user->isDirty('points')) {
event(UserPointsChanged::class);
}
}
}
I want to know how can I include the reason it was created. (reason is also a field of TransactionPoints)
For example, if the User gained points by completing an achievement, I want the string "achievement" to be able to reach the Listener (since Observer triggers the event and the event triggers the listener).
I thought of moving the reason from the TransactionPoints table to the Users table, but I think that would be counter-intuitive and lead to problems later on.
Laravel 5.3+
Not tested, but might help.
create a constructor in your observer that can get request
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
Then in your observer, you can pass the data to event and then to listner
event(new UserPointsChanged($this->request->reason));
Get data in UserPointsChanged Event
public $reason;
public function __construct($reason)
{
$this->transaction = $reason;
}
Then use in handle method.
I'm working with a Resource pivot model between Owners and ResourceDefinition models.
When trades are made, I'm using decrement on the additional pivot "quantity" field:
DB::transaction(function () use ($givenItem, $target, $quantity) {
$target->receive($givenItem, $quantity);
$givenItem->pivot->decrement('quantity', $quantity);
});
I've registered a callable function into the updating event to perform the deletion of the model (and relation):
protected static function booted(): void
{
/**
* Because Resource is just a pivot between its owner and ResourceDefinition
* We need to delete it when it decrease to 0
*/
static::updating(static function (self $model) {
if ($model->quantity <= 0) {
Log::debug('from model');
$model->performDeleteOnModel(); // I've also tried ->delete(), but my model is not deleted....
}
});
}
but for some kind of owner (it's a polymorphical relationship), I need to delete the owner when the quantity hit the ground, so I've created an event which should be fired when deleting the model:
// In my resource model class
protected $dispatchesEvents = [
'deleting' => Deleting::class
];
// My event:
class Deleting
{
public ResourceModel $resource;
public function __construct(ResourceModel $resource)
{
Log::debug('from event');
$this->resource = $resource;
}
}
// My listener
class DestroyAndRespawnCollectableBuilding
{
public function handle(Deleting $event)
{
Log::debug('from listener');
}
}
Listener discovering is activated so I don't need to register the event (all others work fine)
I've used log to not blow your mind with my code-logic, but the result is here, I'm trying to fire the event twice, but no log from the event or listener is registered:
[2020-11-01 21:24:14] local.DEBUG: from model
[2020-11-01 21:23:18] local.DEBUG: from model
Does someone know why this is happening?
I have a destroy function which allows me to detach models (polymorphic relationship).
public function destroy {
$vaccine = HealthItem::findOrFail($vaccine_id);
$vaccine->detachCategories();
$events = $vaccine->events()->get();
foreach ($events as $event) {
$event->detachCategories();
};
$vaccine->events()->delete();
$vaccine->delete();
}
Here, I detach an "event" model with "detachCategories" (a helper to help me detach my categories)
I collect them and I do a foreach. It works, it is well detached from my table categorizable.
BUT I don't think it's great, right?
I'm going to have to do it for all of my events, every time a model is linked to it and it'll do a lot. So, I tried to make it an event but without success.
My Event Model :
protected static function boot()
{
parent::boot();
static::deleting(function ($event) {
$event->categories()->detach();
});
}
I delete the event with the following line $vaccine->events()->delete();
How would you do it?
Laravel Events should get you there, and if its a big job and you have setup queue workers on your server, you should make sure the event listeners are queued.
The following solution should work:
You likely want to make a contract and a trait for this polymorphic relationship so that you can do better type hinting, and DRY up your code. You can put these in whatever folders make most sense for your project. Say:
interface CategorizableContract
{
// Relationship to access the models categories
}
trait HasCategories
{
// Implement methods above
/**
* Initialize the trait
*
* #return void
*/
protected function bootHasCategories()
{
static::deleting(function($categorizable) {
event(new DestroyCategorizable($categorizable));
});
}
}
Then in your models that have categories:
class Vaccine extends Model implements CategorizableContract
{
use HasCategories;
...
}
Now we can make an event in App\Events:
class DestroyCategorizable
{
use SerializesModels;
/** #var CategorizableContract */
public $categorizable;
/**
* Create an event for deleting categorizable models
*
* #param CategorizableContract $categorizable
*
* #return void
*/
public function __construct(CategorizableContract $categorizable)
{
$this->categorizable = $categorizable;
}
}
Now you can make an event listener, in App\Listeners, like so:
class DetachCategories implements ShouldQueue
{
public function handle(DestroyCategorizable $event)
{
$categorizable = $event->categorizable;
$class = new ReflectionClass($categorizable)
// Detach the categories
DB::table('categorizable')
->where('categorizable_type', $class->getName())
->where('categorizable_id', $categorizable->id)
->delete();
}
}
Now just register your listener in your EventServiceProvider, and away you go!
protected $listen = [
DestroyCategorizable::class => [
DetachCategories::class,
],
];
Now when you call delete on a model with categories, it will automatically detach them for you.
$vaccine->delete();
Even though the model is deleted, it was serialized in the event, so its id and class type will be available to detach the categories in the listener. Hope that helps :)
I need help, don't see anything suspicious :c thanks for help !
Error Collection::addEagerConstraints does not exist occurs after the call:
public function show(Request $request, User $user)
{
$user->load('permissions');
dd($with);
return UserResource::make($user);
}
User Model:
class User extends Authenticatable
{
(...)
//////////////////////////////////////////////////////////////////////////////////////////
///
/// Relationships
///
//////////////////////////////////////////////////////////////////////////////////////////
/**
* Relationship to permissions
*
* #return RolePermissions
*/
public function permissions()
{
return $this->role()->first()->permissions;
}
}
if you are using standard laravel user ,
you have to remove your 'permissions' relation and use the ready-made one:
$permissionNames = $user->getPermissionNames(); // collection of name strings
$permissions = $user->permissions; // get the user permissions
if you want a user with its permissions:
$user->load('permissions');
more details in:
https://docs.spatie.be/laravel-permission/v3/basic-usage/basic-usage/
In my database, i have two tables notification and alertFrequency. The notification has field id and website_url and the alert frequency has id and notification_id. Both tables has models which is one to many. The notification can have one or many alertFrequency.
class Notification extends Model {
public function alertFrequencies() {
return $this - > belongsToMany('AlertFrequency::class');
}
}
namespace App;
use Illuminate\ Database\ Eloquent\ Model;
class AlertFrequency extends Model {
protected $table = 'alertFrequencies';
public function notification() {
return $this - > belongsTo(Notification::class);
}
}
in the notification model, i wrote a function called alert, that will give me the laastest alert associated with a specific websie.
public function alert(){
$alert_frequency = AlertFrequency::find('notification_id')->first();
$o_notification = $this->alertFrequencies()->where('notification_id',$alert_frequency->id)
->select('created_at')->orderBy('created_at')->first();
if($alert_frequency ==null){
return false;
}
return created_at;
}
Is this a right way to extract the data? i would appreciate any suggestions and helps?
Notification hasMany AlertFrequency
public function alertFrequencies(){
return $this->hasMany('App\AlertFrequency');
}
and,
$alert_frequency = AlertFrequency::with('notification')->orderBy('created_at','desc')->first();
loads the latest AlertFrequency along with it's notification.
See One to Many relationship and Eager loading in documentation.
to get laastest alert associated with a specific websie with url $website_url.
Notification::where('website_url', $website_url)->orderBy('created_at')->first();
hasMany relation :
public function alertFrequencies(){
return $this->hasMany('App\AlertFrequency','notification_id');
}