Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Michael Fayez's avatar

What's missing in my code ! 10 Dollars for the person who solve this problem :)

I want to send emails to the assignees + admins for every action Here is my User Model

<?php

namespace App\Models;

use App\Models\UserAlert;
use App\Support\HasAdvancedFilter;
use App\Traits\HasTeam;
use Carbon\Carbon;
use DateTimeInterface;
use Hash;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Contracts\Translation\HasLocalePreference;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable implements HasLocalePreference, MustVerifyEmail
{
    use HasFactory, HasAdvancedFilter, Notifiable, HasTeam, SoftDeletes;

    public $table = 'users';

    protected $casts = [
        'is_approved' => 'boolean',
    ];

    protected $hidden = [
        'remember_token',
        'password',
    ];

    protected $dates = [
        'email_verified_at',
        'created_at',
        'updated_at',
        'deleted_at',
    ];

    protected $fillable = [
        'name',
        'email',
        'password',
        'locale',
        'team_id',
        'is_approved',
    ];

    public $orderable = [
        'id',
        'name',
        'email',
        'email_verified_at',
        'locale',
        'team.name',
        'is_approved',
    ];

    public $filterable = [
        'id',
        'name',
        'email',
        'email_verified_at',
        'roles.title',
        'locale',
        'team.name',
    ];

    public function getIsAdminAttribute()
    {
        return $this->roles()->where('title', 'Admin')->exists();
    }

    public function scopeAdmins()
    {
        return $this->whereHas('roles', fn ($q) => $q->where('title', 'Admin'));
    }

    public function alerts()
    {
        return $this->belongsToMany(UserAlert::class)->withPivot('seen_at');
    }

    public function preferredLocale()
    {
        return $this->locale;
    }

    protected function serializeDate(DateTimeInterface $date)
    {
        return $date->format('Y-m-d H:i:s');
    }

    public function getEmailVerifiedAtAttribute($value)
    {
        return $value ? Carbon::createFromFormat('Y-m-d H:i:s', $value)->format(config('project.datetime_format')) : null;
    }

    public function setEmailVerifiedAtAttribute($value)
    {
        $this->attributes['email_verified_at'] = $value ? Carbon::createFromFormat(config('project.datetime_format'), $value)->format('Y-m-d H:i:s') : null;
    }

    public function setPasswordAttribute($input)
    {
        if ($input) {
            $this->attributes['password'] = Hash::needsRehash($input) ? Hash::make($input) : $input;
        }
    }

    public function roles()
    {
        return $this->belongsToMany(Role::class);
    }

    public function getCreatedAtAttribute($value)
    {
        return $value ? Carbon::createFromFormat('Y-m-d H:i:s', $value)->format(config('project.datetime_format')) : null;
    }

    public function getUpdatedAtAttribute($value)
    {
        return $value ? Carbon::createFromFormat('Y-m-d H:i:s', $value)->format(config('project.datetime_format')) : null;
    }

    public function getDeletedAtAttribute($value)
    {
        return $value ? Carbon::createFromFormat('Y-m-d H:i:s', $value)->format(config('project.datetime_format')) : null;
    }

    public function team()
    {
        return $this->belongsTo(Team::class);
    }

    
}

Here is my Project Model :-

<?php

namespace App\Models;

use App\Support\HasAdvancedFilter;
use App\Traits\Auditable;
use App\Traits\Tenantable;
use Carbon\Carbon;
use DateTimeInterface;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Project extends Model
{
    use HasFactory, HasAdvancedFilter, SoftDeletes, Tenantable, Auditable;

    public $table = 'projects';

    public const STATUES_RADIO = [
        'active' => 'Active',
        'hold'   => 'Hold',
        'closed' => 'Closed',
    ];

    protected $dates = [
        'created_at',
        'start_date',
        'end_date',
        'updated_at',
        'deleted_at',
    ];

    protected $fillable = [
        'name',
        'owner_id',
        'start_date',
        'end_date',
        'statues',
        'team_id',
    ];

    public $orderable = [
        'id',
        'name',
        'owner.name',
        'created_at',
        'start_date',
        'end_date',
        'statues',
        'updated_at',
        'deleted_at',
        'team.name',
    ];

    public $filterable = [
        'id',
        'name',
        'owner.name',
        'created_at',
        'package.name',
        'start_date',
        'end_date',
        'statues',
        'assignee.email',
        'updated_at',
        'deleted_at',
        'team.name',
    ];



    protected function serializeDate(DateTimeInterface $date)
    {
        return $date->format('Y-m-d H:i:s');
    }

    public function owner()
    {
        return $this->belongsTo(User::class);
    }

    public function getCreatedAtAttribute($value)
    {
        return $value ? Carbon::createFromFormat('Y-m-d H:i:s', $value)->format(config('project.datetime_format')) : null;
    }

    public function package()
    {
        return $this->belongsToMany(Package::class);
    }

    public function getStartDateAttribute($value)
    {
        return $value ? Carbon::parse($value)->format(config('project.date_format')) : null;
    }

    public function setStartDateAttribute($value)
    {
        $this->attributes['start_date'] = $value ? Carbon::createFromFormat(config('project.date_format'), $value)->format('Y-m-d') : null;
    }

    public function getEndDateAttribute($value)
    {
        return $value ? Carbon::parse($value)->format(config('project.date_format')) : null;
    }

    public function setEndDateAttribute($value)
    {
        $this->attributes['end_date'] = $value ? Carbon::createFromFormat(config('project.date_format'), $value)->format('Y-m-d') : null;
    }

    public function getStatuesLabelAttribute($value)
    {
        return static::STATUES_RADIO[$this->statues] ?? null;
    }

    public  function assignee()
    {
        return $this->belongsToMany(User::class);
    }

    public function getUpdatedAtAttribute($value)
    {
        return $value ? Carbon::createFromFormat('Y-m-d H:i:s', $value)->format(config('project.datetime_format')) : null;
    }

    public function getDeletedAtAttribute($value)
    {
        return $value ? Carbon::createFromFormat('Y-m-d H:i:s', $value)->format(config('project.datetime_format')) : null;
    }

    public function team()
    {
        return $this->belongsTo(Team::class);
    }
}

Here is my ProjectObserver :-

<?php

namespace App\Observers;

use App\Models\Project;
use App\Models\User;
use App\Notifications\DataChangeEmailNotification;
use Notification;

class ProjectObserver
{
    public function created(Project $project): void
    {
        $payload = [
            'action' => 'created',
            'model'  => sprintf('%s#%s', get_class($project), $project->id),
            'reason' => auth()->user(),
        ];

        $admins = User::admins()->get();

        Notification::send($admins, new DataChangeEmailNotification($payload));
    }

    public function updated(Project $project): void
    {
        $payload = [
            'action' => 'updated',
            'model'  => sprintf('%s#%s', get_class($project), $project->id),
            'reason' => auth()->user(),
        ];

        $admins = User::admins()->get();

        Notification::send($admins, new DataChangeEmailNotification($payload));
    }

    public function deleted(Project $project): void
    {
        $payload = [
            'action' => 'deleted',
            'model'  => sprintf('%s#%s', get_class($project), $project->id),
            'reason' => auth()->user(),
        ];

        $admins = User::admins()->get();

        Notification::send($admins, new DataChangeEmailNotification($payload));
    }
}

here my migration :-

  Schema::create('project_user', function (Blueprint $table) {
            $table->unsignedBigInteger('project_id');
            $table->foreign('project_id', 'project_id_fk_9107252')->references('id')->on('projects')->onDelete('cascade');
            $table->unsignedBigInteger('user_id');
            $table->foreign('user_id', 'user_id_fk_9107252')->references('id')->on('users')->onDelete('cascade');
        });

How to send emails to Admin + Assignee ???

0 likes
13 replies
Snapey's avatar
$assignees = $this->assignees()->get();

Notification::send($assignees, new DataChangeEmailNotification($payload));

or

$this->loadMissing('assignees');

Notification::send($this->assignees, new DataChangeEmailNotification($payload));
Talinon's avatar

If you are implementing the ShouldQueue interface on your DataChangeEmailNotification class, make sure you restart your queue workers so that the changes take effect in memory.

Michael Fayez's avatar

@Talinon not yet I want to send to the Assignee email that's really important to me and after that will use Queue

Snapey's avatar

@Michael Fayez So you appreciate how useless is a response of "not working"?

What happens?

What debugging have you attempted?

Michael Fayez's avatar

@Snapey it send only for admin, not assignee , when I made dd() this is the code

Illuminate\Database\Eloquent\Collection {#2599 ▼ // app/Observers/ProjectObserver.php:27
  #items: array:1 [▼
    0 => App\Models\User {#2598 ▼
      #connection: "mysql"
      +table: "users"
      #primaryKey: "id"
      #keyType: "int"
      +incrementing: true
      #with: []
      #withCount: []
      +preventsLazyLoading: false
      #perPage: 15
      +exists: true
      +wasRecentlyCreated: false
      #escapeWhenCastingToString: false
      #attributes: array:12 [▶]
      #original: array:12 [▶]
      #changes: []
      #casts: array:2 [▶]
      #classCastCache: []
      #attributeCastCache: []
      #dateFormat: null
      #appends: []
      #dispatchesEvents: []
      #observables: []
      #relations: []
      #touches: []
      +timestamps: true
      +usesUniqueIds: false
      #hidden: array:2 [▶]
      #visible: []
      #fillable: array:6 [▶]
      #guarded: array:1 [▶]
      #rememberTokenName: "remember_token"
      #dates: array:4 [▶]
      +orderable: array:7 [▶]
      +filterable: array:7 [▶]
      #forceDeleting: false
    }
  ]
  #escapeWhenCastingToString: false
}
``
Still not working 
Michael Fayez's avatar
Illuminate\Database\Eloquent\Collection {#2599 ▼ // app/Observers/ProjectObserver.php:27
  #items: array:1 [▼
    0 => App\Models\User {#2598 ▼
      #connection: "mysql"
      +table: "users"
      #primaryKey: "id"
      #keyType: "int"
      +incrementing: true
      #with: []
      #withCount: []
      +preventsLazyLoading: false
      #perPage: 15
      +exists: true
      +wasRecentlyCreated: false
      #escapeWhenCastingToString: false
      #attributes: array:12 [▼
        "id" => 1
        "name" => "Admin"
        "email" => "[email protected]"
        "email_verified_at" => "2023-10-14 11:54:16"
        "password" => "y$Jh2xanU2EsMevsrTHAps9OUPVb68tJBQrD4h7v2rIoFnW0XXnXwS6"
        "remember_token" => null
        "locale" => ""
        "is_approved" => 1
        "created_at" => null
        "updated_at" => null
        "deleted_at" => null
        "team_id" => null
      ]
      #original: array:12 [▼
        "id" => 1
        "name" => "Admin"
        "email" => "[email protected]"
        "email_verified_at" => "2023-10-14 11:54:16"
        "password" => "y$Jh2xanU2EsMevsrTHAps9OUPVb68tJBQrD4h7v2rIoFnW0XXnXwS6"
        "remember_token" => null
        "locale" => ""
        "is_approved" => 1
        "created_at" => null
        "updated_at" => null
        "deleted_at" => null
        "team_id" => null
      ]
      #changes: []
      #casts: array:2 [▼
        "is_approved" => "boolean"
        "deleted_at" => "datetime"
      ]
      #classCastCache: []
      #attributeCastCache: []
      #dateFormat: null
      #appends: []
      #dispatchesEvents: []
      #observables: []
      #relations: []
      #touches: []
      +timestamps: true
      +usesUniqueIds: false
      #hidden: array:2 [▶]
      #visible: []
      #fillable: array:6 [▶]
      #guarded: array:1 [▶]
      #rememberTokenName: "remember_token"
      #dates: array:4 [▶]
      +orderable: array:7 [▶]
      +filterable: array:7 [▶]
      #forceDeleting: false
    }
  ]
  #escapeWhenCastingToString: false
}
Michael Fayez's avatar

@Snapey in ProjectObserver :-


    public function created(Project $project): void
    {
        $payload = [
            'action' => 'created',
            'model'  => sprintf('%s#%s', get_class($project), $project->id),
            'reason' => auth()->user(),
        ];

        $admins = User::admins()->get();
        $assignees = $project->assignee()->get();

        $recipients = $admins->concat($assignees);
        dd($recipients);

        Notification::send($recipients, new DataChangeEmailNotification($payload));
    }
Snapey's avatar

@Michael Fayez You do not have an assignee relationship in your model (which is why I wrote assignees)

Michael Fayez's avatar

@Snapey Call to undefined method App\Observers\ProjectObserver::assignees()

public function created(Project $project): void

    {

        $payload = [

            'action' => 'created',

            'model'  => sprintf('%s#%s', get_class($project), $project->id),

            'reason' => auth()->user(),

        ];



        $admins = User::admins()->get();

        $assignees = $this->assignees()->get();



        $recipients = $admins->concat($assignees);

        dd($recipients);



        Notification::send($recipients, new DataChangeEmailNotification($payload));

    }

what shall I do :)

Snapey's avatar

@Michael Fayez you should learn about observers, and then you would see my simple mistake and fix it 2 hours ago

since your observer is outside of the model, you need to use the passed in project

$assignees = $project->assignees()->get();

Please or to participate in this conversation.