发送邮件时触发Call to a member function getRealPath() on string错误
解决Laravel发送邮件时
Call to a member function getRealPath() on string错误 问题重现
发送邮件时触发错误,错误指向邮件类中调用getRealPath()的代码行:
->attach($this->data['resume']->getRealPath(),
相关代码如下:
控制器代码
public function store(CareerRequest $request) { $requestData = $request->all(); $filenameWithExt = $request->file('resume')->getClientOriginalName(); $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME); $extension = $request->file('resume')->getClientOriginalExtension(); $fileNameToStore = $filename.'_'.time().'.'.$extension; $request->file('resume')->storeAs('candidateResume', $fileNameToStore); $requestData["resume"] = $fileNameToStore ; Career::create($requestData); return redirect()->back(); }
邮件类(Mailable)代码
class CareerMail extends Mailable { public $data; public function __construct($data) { $this->data = $data; } public function build() { return $this->subject('Career - '. $this->data->subject) ->view('emails.career') ->attach($this->data['resume']->getRealPath(), [ 'as' => $this->data['resume']->getClientOriginalName(), 'mime' => $this->data['resume']->getClientMimeType(), ]); } }
错误原因
控制器中已经将上传的文件存储到服务器,并将**存储后的文件名(字符串)**赋值给$requestData["resume"]存入数据库。但邮件类中错误地将这个字符串当作UploadedFile对象,调用了只有文件对象才有的getRealPath()、getClientOriginalName()等方法,导致类型错误。
解决方案
方案1:传递原始文件对象到邮件类(适用于存储文件后立即发邮件的场景)
如果在控制器存储文件后需要立即发送邮件,可以直接将原始的UploadedFile对象传递给邮件类,同时保留存储文件名到数据库的逻辑:
修改控制器代码:
public function store(CareerRequest $request) { $requestData = $request->all(); $filenameWithExt = $request->file('resume')->getClientOriginalName(); $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME); $extension = $request->file('resume')->getClientOriginalExtension(); $fileNameToStore = $filename.'_'.time().'.'.$extension; $request->file('resume')->storeAs('candidateResume', $fileNameToStore); $requestData["resume"] = $fileNameToStore ; Career::create($requestData); // 传递原始文件对象到邮件类 Mail::to('recipient@example.com')->send(new CareerMail([ 'subject' => $requestData['subject'], 'resume' => $request->file('resume') ])); return redirect()->back(); }
邮件类代码无需修改,此时$this->data['resume']是UploadedFile对象,可以正常调用相关方法。
方案2:从存储路径获取文件信息(适用于从数据库读取数据后发邮件的场景)
如果是从数据库读取已存储的记录来发送邮件,需要通过存储的文件名获取文件的真实路径和MIME类型,同时建议存储原始文件名到数据库以优化邮件附件显示:
步骤1:修改控制器,存储原始文件名到数据库
public function store(CareerRequest $request) { $requestData = $request->all(); $filenameWithExt = $request->file('resume')->getClientOriginalName(); $filename = pathinfo($filenameWithExt, PATHINFO_FILENAME); $extension = $request->file('resume')->getClientOriginalExtension(); $fileNameToStore = $filename.'_'.time().'.'.$extension; $request->file('resume')->storeAs('candidateResume', $fileNameToStore); // 新增存储原始文件名 $requestData["resume"] = $fileNameToStore ; $requestData["resume_original_name"] = $filenameWithExt; Career::create($requestData); return redirect()->back(); }
步骤2:修改邮件类,通过文件名获取文件信息
class CareerMail extends Mailable { public $data; public function __construct($data) { $this->data = $data; } public function build() { $filePath = storage_path('app/candidateResume/' . $this->data['resume']); $mimeType = \Illuminate\Support\Facades\Storage::mimeType('candidateResume/' . $this->data['resume']); return $this->subject('Career - '. $this->data->subject) ->view('emails.career') ->attach($filePath, [ 'as' => $this->data['resume_original_name'], 'mime' => $mimeType, ]); } }
这样就能正确获取文件的真实路径和相关信息,避免类型错误。
内容的提问来源于stack exchange,提问作者Dev Patil
相关产品推荐
相关产品推荐

