Meaulnes
Meaulnes

Reputation: 487

LARAVEL 7 :ErrorException Undefined index

I encounter an error using an array index in an email html template despite the fact that the index is defined as other indexes in the same array.

The trouble occurs when using the incriminated index in the email template. As far as I don't use it things are as described below.

Things start with a controller function to send an email

   public function sendToOne(Request $request){
        if ($request->ajax()) {
            $this->validate($request, [
            'user_id'=>'required',
            'infoletter_id'=>'required'
            ]);
            Log::debug('entering sendToOne with user_id '.$request->user_id);
            $infoletter=Infoletter::find($request->infoletter_id);
            $user=User::find( $request->user_id);
            $sender=User::find(1);
            $details=[
                'title'=>$infoletter->title,
                'body'=>$infoletter->body,
                'sender'=>$sender,
                'user'=>$user,
            ];
            $job=(new SendEmailJob($details))->delay($request->delay);
            dispatch($job);
            $duree=$request->delay;
            $minutes=intval(($duree % 3600) / 60);
            $secondes=intval((($duree % 3600) % 60));
            return response()->json(['success'=>'Envoi de l\'infolettre programmé pour '.$user->firstname.' '.$user->familyname .'. L\'envoi aura lieu dans '.$minutes.' minutes et '.$secondes.' secondes.']);
        }
        else{ return 'request is not ajax';}
    }

The array involved is $details in which I pass a sender (User class) as well as a user (User class also) the recipient of the mail. The SendEmailJob is called with $details array as argument.

Then comes the SendEmailJob

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Mail\InfoletterMail;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Log;
use Carbon\carbon;

class SendEmailJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    protected $details;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($details)
    {
        $this->details=$details;
    }
    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {  
             Log::debug('entering function handle in SendEmailJob');
             Log::debug($this->details);
            $email = new InfoletterMail($this->details);           
            Mail::to($this->details['user']->email)->send($email);              
     }  
}

its constructor receive the details array as argument, and in the handle function we instantiate an InfoletterMail passing it the same array. Notice that at this stage,assuming I don't use the incriminated index to prevent the error, the log (Log::debug($this->details);) shows the the 'sender' index is present.

Then comes the InfoletterMail

<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;

class InfoletterMail extends Mailable
{
    use Queueable, SerializesModels;
    protected $details;
    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct($details)
    {
        $this->details=$details;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()

    {
        Log::debug('entering build in InfoletterMail');
        Log::debug($this->details);
        return $this->view('emails.infoletter')->with('details',$this->details);
    }
}

At this stage, ,assuming I don't use the incriminated index to prevent the error,the log (Log::debug($this->details);) shows that the 'sender' index is present and correct.

Then comes the email's view (emails.infoletter) assuming I use the incriminated index ('sender')

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    @include('emails.inc.intro')
   <p style="text-align: center;"> Bonjour {{$details['user']->firstname}} {{$details['user']->familyname}} ,</p>
    <div>
        {{$details['body']}}
    </div>
   <p style="text-align: center;"> Bien à vous,</p>
   <p style="text-align: center;">{{$details['sender']->firstname}} {{$details['sender']->familyname}}</p>

</body>
</html>

Then comes the error

Undefined index: sender (View: /ORIGINAL-P1/LARAVEL/denentzat/resources/views/emails/infoletter.blade.php)

I cannot make out where the error comes from and I need help.

Upvotes: 1

Views: 3851

Answers (1)

Meaulnes
Meaulnes

Reputation: 487

I eventually made it out. It's a bit difficult to explain thus I will do my best to be clear.

In fact, the email is sent from a view page where it is presented to the sender before sending it.

The user has different buttons one to send to all users, and other to send to a restrict number of user etc.

Has I intend to space the emails with delay I use a jquery script to loop over the users. In each loop I do an ajax request to the sendToOne action in the controller. The controller responds to the ajax request instantiating a Job (SendMailJob) that itself instantiates a mailable (InfoletterMail) that uses the email template with the parameter $details that is an array including the 'sender' index.

All this would be correct if I didn't previously use the same email template in the view I spoke of at the beginning to display a preview of the mail but forgetting to add the 'sender' index to the $details I passed to it. In fact the error was not created by the mail itself, but by the preview instead. For the ones that are interested, here is this view with the lines that create the preview and where I forgot to add 'sender' index.

$emailview=view('emails.infoletter')->with('details', ['title'=>$infoletter->title, 'body'=>$infoletter->body,'user'=>$fakeuser,'sender'=>auth()->user()]);
{!!html_entity_decode($emailview)!!}

Code of the view

@extends('layouts.bare')


@section('content')

<div class="container mt-4 my-content">
    <div id='messages'>

    </div>  
 

    <div class="d-flex">
                    <a href="/infoletters" class="my-button">Retourner à la liste</a>
                    <a href="" class="my-button">Modifier</a>
                    
            
                <div>
                    {{--below a form with a submit button that will be intercepted by the java script at the bottom of page--}}   
                    {{--The script will trigger ajax requests / one per user--}}
                    {!! Form::open([]) !!}
                        <div class="row post-option-background">
                            <div class="col-md-12" >
                                {{ Form::hidden('infoletter_id', $infoletter->id) }}{{--permetra de retrouver title et body--}}
                                {{ Form::hidden('users', $users )}}{{--permetra de boucler dans jquery--}}
                            
                            </div>
                        </div>
                        {{Form::submit('Envoyer a tous',['class'=>'my-button btn  btn-submit btn-to-all','id'=>'btn-to-all'])}}

                    {!! Form::close() !!}
                </div>
                <div>
                    {{--below a form with a submit button that will be intercepted by the java script at the bottom of page--}}   
                    {{--The script will trigger ajax requests / one per user--}}
                    {!! Form::open([]) !!}
                        <div class="row post-option-background">
                            <div class="col-md-12" >
                                {{ Form::hidden('infoletter_id', $infoletter->id) }}{{--permetra de retrouver title et body--}}
                                {{ Form::hidden('users', $users )}}{{--permetra de boucler dans jquery--}}
                            
                            </div>
                        </div>
                        {{Form::submit('Envoyer au CA',['class'=>'my-button btn  btn-submit btn-to-CA','id'=>'btn-to-CA'])}}

                    {!! Form::close() !!}
                </div>
                <div>
                    {{--below a form with a submit button that will be intercepted by the java script at the bottom of page--}}   
                    {{--The script will trigger ajax requests / one per user--}}
                    {!! Form::open([]) !!}
                        <div class="row post-option-background">
                            <div class="col-md-12" >
                                {{ Form::hidden('infoletter_id', $infoletter->id) }}{{--permetra de retrouver title et body--}}
                                {{ Form::hidden('user_id',  Auth::user()->id )}}
                            
                            </div>
                        </div>
                        {{Form::submit('Envoyer à moi-même (test)',['class'=>'my-button btn  btn-submit btn-to-me','id'=>'btn-to-me'])}}

                    {!! Form::close() !!}
                </div>  

    </div>

</div>  
                
<div class="container mt-4 my-content"> 
    
    

    <div class="my-post-body">
        {!!html_entity_decode($emailview)!!}
        
    </div>      
</div>  

<script type="text/javascript">
    $( document ).ready(function() {
        //$('#messages').append('<h1> Le java scirpt fonctionne</h1>');
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
                
            }
        });

        $('#btn-to-all').click(function(e){ 
            e.preventDefault();
            var infoletter_id = $("input[name=infoletter_id]").val();
            var users = $("input[name=users]").val();
            parsed_users=JSON.parse(users);
            var i=0;
            var url='{{ url('infoletters/sendToOne') }}';
            delay=0;
            for (i=0; i<parsed_users.length;i++){
                $.ajax({
                    type:'POST',
                    url:url,
                    data:{user_id:parsed_users[i].id,infoletter_id:infoletter_id,delay:delay},
                    dataType: 'json',
                    success:function(data){
                        $('#messages').prepend('<div class="comments-message" style="margin-bottom:15px;padding:5px;background-color: green; color: white; margin-top:5px;">'+data['success']+'!.</div>');
                    }
                });
                delay=delay+3;
            }   
        });
        $('#btn-to-CA').click(function(e){  
            e.preventDefault();
            var CAMembers=[23,1,4,12,55,19,7,17,18,10,25,5,24];
            var infoletter_id = $("input[name=infoletter_id]").val();
            var users = $("input[name=users]").val();
            parsed_users=JSON.parse(users);
            var i=0;
            var url='{{ url('infoletters/sendToOne') }}';
            delay=0;
            for (i=0; i<parsed_users.length;i++){
                if(CAMembers.includes(parsed_users[i].id)){
                    $.ajax({
                        type:'POST',
                        url:url,
                        data:{user_id:parsed_users[i].id,infoletter_id:infoletter_id,delay:delay},
                        dataType: 'json',
                        success:function(data){
                            $('#messages').prepend('<div class="comments-message" style="margin-bottom:15px;padding:5px;background-color: green; color: white; margin-top:5px;">'+data['success']+'!.</div>');
                        }
                    });
                delay=delay+3;

                }
            }   
        });

        $('#btn-to-me').click(function(e){  
            $('#messages').prepend('<div class="comments-message" style="margin-bottom:15px;padding:5px;background-color: green; color: white; margin-top:5px;">Le script fonctionne.</div>');
            e.preventDefault();
            var infoletter_id = $("input[name=infoletter_id]").val();
            var user_id = $("input[name=user_id]").val();
            var url='{{ url('infoletters/sendToOne') }}';
            $.ajax({
                    type:'POST',
                    url:url,
                    data:{user_id:user_id,infoletter_id:infoletter_id},
                    dataType: 'json',
                    success:function(data){
                        $('#messages').prepend('<div class="comments-message" style="margin-bottom:15px;padding:5px;background-color: green; color: white; margin-top:5px;">'+data['success']+'!.</div>');
                    }
                });
                
        });

        
    });
    </script>
@endsection

and the controller action where an other $details is passed to the view and that was the cause of the trouble

  public function view($id)
    {
        //we empty the job tables
        Job::truncate();
        Failed_job::truncate();
        Log::emergency('Entering infoletter@view');
        Log::debug('Entering infoletter@view');
        $infoletter=Infoletter::find($id);
        $users=User::all();
     
        $fakeuser=new User();// to simulate the user in the presentation of the mail in the view
        $fakeuser->firstname='Prénom';
        $fakeuser->familyname='Fake name';
        $emailview=view('emails.infoletter')->with('details', ['title'=>$infoletter->title, 'body'=>$infoletter->body,'user'=>$fakeuser,'sender'=>auth()->user()]);
        return view('infoletters.view', compact('infoletter', 'users', 'emailview'));//here we pass a fake email view as example to bee shown
    }

Upvotes: 1

Related Questions