InvalidArgumentException : View [themes.] not found - laravel

I get the following error message out of the blue.
InvalidArgumentException : View [themes.] not found.
Exception trace:
1 Illuminate\View\FileViewFinder::findInPaths("themes.")
C:\xampp\htdocs\RoosterIKEA\vendor\laravel\framework\src\Illuminate\View\FileViewFinder.php:92
2 Illuminate\View\FileViewFinder::findNamespacedView("mail::themes.")
C:\xampp\htdocs\RoosterIKEA\vendor\laravel\framework\src\Illuminate\View\FileViewFinder.php:76
Any idea which file this could be and what is going on?

In the class Illuminate\Mail\Markdown line 64
return new HtmlString(($inliner ?: new CssToInlineStyles)->convert(
$contents, $this->view->make('mail::themes.'.$this->theme)->render()
));
It appears that $this->theme is an empty string
Now the class already defines the property on line 24
/**
* The current theme being used when generating emails.
*
* #var string
*/
protected $theme = 'default';
Which means that you may have overridden this property by an empty string or maybe a null value in your markdown mailable
If you publish the components by
php artisan vendor:publish --tag=laravel-mail
You'll see a CSS file in resources/views/vendor/mail/html/themes named default.css
I found a way to reproduce this error on purpose to have a Mailable class like so
Run
php artisan make:mail OrderShipped --markdown=emails.orders.shipped
Then override the theme property by an empty string
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class OrderShipped extends Mailable
{
use Queueable, SerializesModels;
protected $theme = ''; // <--- HERE
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('emails.orders.shipped');
}
}
Now send an email
use App\User;
use App\Mail\OrderShipped;
Route::get('/', function () {
\Mail::to(User::first())->send(new OrderShipped());
});
And you would get the same error
The solution here is to either remove the protected $theme = ''; property or set it to default
I hope this helps

Related

Laravel mail with attachment gives fopen(): null bytes error

I am trying to send an email with a pdf file attached to it.
I checked and the file does exist at the path. I can open it aswell.
I tested if i can download the file with the download function of the storage facade and that also worked.
However when i try it in a queued email, it fails everytime after waiting about 20 seconds.
This is the error i got:
ValueError: fopen(): Argument #1 ($filename) must not contain any null bytes in C:\Users\Gebruiker\PhpstormProjects\FuegoWebsite\vendor\swiftmailer\swiftmailer\lib\classes\Swift\ByteStream\FileByteStream.php:129
Stack trace:
And my email code is:
<?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\App;
use Illuminate\Support\Facades\Storage;
class PdfTestMail extends Mailable
{
use Queueable, SerializesModels;
public $orderId;
public $text;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($orderid, $text)
{
$this->orderId = $orderid;
$this->text = $text;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$file = Storage::disk('private')->get("factuur_order_".$this->orderId.'.pdf');
return $this->text('emails.notifyAdmin')
->subject('Orderbevestiging #'.$this->orderId)
->attach($file, [
'as' => 'factuur.pdf',
'mime' => 'application/pdf'
]);
}
}
I tried to attach the pdf in multiple ways, including the direct output of the barryvdh/dompdf package i use to generate a pdf.
nothing works and i have no idea why.
The attach method takes a filename for the file to attach, not data. You are probably looking for the attachData method:
public function attachData($data, $name, array $options = [])
To switch to attachData:
->attachData($file, 'factuur.pdf', ['mime' => 'application/pdf'])
Laravel 8.x Docs - Mail - Attachments - Raw Data Attachments attachData

Unit Testing Events in Laravel 8 throw EventFake::__construct() must implement interface Illuminate\Contracts\Events\Dispatcher, null given

I'm trying to fake an event using Unit Testing, so no DB, no Application, just pure classes.
I'm following the documentation for Laravel 8, my current version, but I'm still getting the error
1) Tests\Unit\HandShake\ConfirmApplicationHandShakeActionTest::BasedOnAnExistentAppIConfirmTheHandShake
TypeError: Argument 1 passed to Illuminate\Support\Testing\Fakes\EventFake::__construct() must implement interface Illuminate\Contracts\Events\Dispatcher, null given, called in /Users/pablo/Workspace/xxxx/vendor/laravel/framework/src/Illuminate/Support/Facades/Event.php on line 38
As you can see is asking for an object implementing the interface Dispatch, my Event has the trait dispatch, but anyways here it says that I'm passing null
My Test code is the one as follow
<?php
namespace Tests\Unit\HandShake;
use App\Actions\ConfirmApplicationHandShakeAction;
use App\Events\HandShakeReceivedEvent;
use App\Exceptions\NotFoundApplicationException;
use App\Models\Application;
use Illuminate\Support\Facades\Event;
use Mockery\MockInterface;
use Mockery;
use PHPUnit\Framework\TestCase;
class ConfirmApplicationHandShakeActionTest extends TestCase
{
/**
*
* #test
* #throws NotFoundApplicationException
*/
public function BasedOnAnExistentAppIConfirmTheHandShake()
{
$appName = 'testDummy';
Event::fake([HandShakeReceivedEvent::class]);
$applicationModel = Mockery::mock(Application::class, function (MockInterface $mock) {
$mock->shouldReceive('exists')
->andReturn(true)
->once();
});
$confirmation = new ConfirmApplicationHandShakeAction($applicationModel);
$confirmation->execute($appName);
The Class that I'm testing is
<?php
declare(strict_types=1);
namespace App\Actions;
use App\Events\HandShakeReceivedEvent;
use App\Exceptions\NotFoundApplicationException;
use App\Models\Application;
/**
* Class ConfirmApplicationHandShakeAction
* #package App\Actions
*/
class ConfirmApplicationHandShakeAction
{
/**
* #var Application
*/
private $application;
/**
* ConfirmApplicationHandShakeAction constructor.
* #param Application $application
*/
public function __construct(Application $application)
{
$this->application = $application;
}
/**
* #param string $appName
* #throws NotFoundApplicationException
*/
public function execute(string $appName)
{
if ( ! $this->application->exists($appName)) {
throw new NotFoundApplicationException('The Application do not exists or is not active');
}
HandShakeReceivedEvent::dispatch($appName);
}
}
Lastly the event is
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class HandShakeReceivedEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('channel-name');
}
}
Probably is one of those moments where I'm missing a stupid character, but I went through this error, and I cannot find the right solution.
UPDATE
I keep digging and I found that the getFacadeRoot() is returning null, so I'm assuming that something is not properly initialized, still not clue
static::swap($fake = new EventFake(static::getFacadeRoot(), $eventsToFake));
Thank you in advance if you find the issue or can point me in the right direction. I also tried FakeFor and Fake without sending the event as a parameter
Problem solved
When you create the test files with artisan, for some reasons the PHPUnit\Framework\TestCase they use is the one in PHPUnit, but they should use the one in Laravel Tests\TestCase
Extending your tests with Tests\TestCase will sort the problem

Laravel Email Verification Template Location

I have been reading from the documentation about the new feature of laravel the email verification. Where can I locate the email template that is sent to the user? It does not show here: https://laravel.com/docs/5.7/verification#after-verifying-emails
Laravel uses this method of VerifyEmail notification class for send email:
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable);
}
return (new MailMessage)
->subject(Lang::getFromJson('Verify Email Address'))
->line(Lang::getFromJson('Please click the button below to verify your email address.'))
->action(
Lang::getFromJson('Verify Email Address'),
$this->verificationUrl($notifiable)
)
->line(Lang::getFromJson('If you did not create an account, no further action is required.'));
}
Method in source code.
If you wanna use your own Email template, you can extend Base Notification Class.
1) Create in app/Notifications/ file VerifyEmail.php
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\Facades\Lang;
use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailBase;
class VerifyEmail extends VerifyEmailBase
{
// use Queueable;
// change as you want
public function toMail($notifiable)
{
if (static::$toMailCallback) {
return call_user_func(static::$toMailCallback, $notifiable);
}
return (new MailMessage)
->subject(Lang::getFromJson('Verify Email Address'))
->line(Lang::getFromJson('Please click the button below to verify your email address.'))
->action(
Lang::getFromJson('Verify Email Address'),
$this->verificationUrl($notifiable)
)
->line(Lang::getFromJson('If you did not create an account, no further action is required.'));
}
}
2) Add to User model:
use App\Notifications\VerifyEmail;
and
/**
* Send the email verification notification.
*
* #return void
*/
public function sendEmailVerificationNotification()
{
$this->notify(new VerifyEmail); // my notification
}
Also if you need blade template:
laravel will generate all of the necessary email verification views
when the make:auth command is executed. This view is placed in
resources/views/auth/verify.blade.php. You are free to customize
this view as needed for your application.
Source.
Answer in comment already. Sent by the toMail() method.
vendor\laravel\framework\src\Illuminate\Auth\Notifications\VerifyEmail::toMail();
For template structure and appearance; take a look at this locations also and you can also publish to modify the template:
\vendor\laravel\framework\src\Illuminate\Notifications\resources\views\email.blade.php
\vendor\laravel\framework\src\Illuminate\Mail\resources\views\
To publish those locations:
php artisan vendor:publish --tag=laravel-notifications
php artisan vendor:publish --tag=laravel-mail
After running this command, the mail notification templates will be located in the resources/views/vendor directory.
Colors and style are controlled by the CSS file in resources/views/vendor/mail/html/themes/default.css
Also, if you want to translate standard mail VerifyEmail (or other where use Lang::fromJson(...)), you need create new json file in resources/lang/ and name it ru.json, for example.
It may contain (resources/lang/ru.json) text below and must be valid.
{
"Verify Email Address" : "Подтверждение email адреса"
}
Actually they do not use any blade or template files. They create notifications and write code for it in notifications.
Look I do that very easy
do the following steps :
In Route File
Auth::routes(['verify' => true]);
In AppServiceProvider.php File
namespace App\Providers;
use App\Mail\EmailVerification;
use Illuminate\Support\ServiceProvider;
use View;
use URL;
use Carbon\Carbon;
use Config;
use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Notifications\Messages\MailMessage;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
// Override the email notification for verifying email
VerifyEmail::toMailUsing(function ($notifiable){
$verifyUrl = URL::temporarySignedRoute('verification.verify',
\Illuminate\Support\Carbon::now()->addMinutes(\Illuminate\Support\Facades
\Config::get('auth.verification.expire', 60)),
[
'id' => $notifiable->getKey(),
'hash' => sha1($notifiable->getEmailForVerification()),
]
);
return new EmailVerification($verifyUrl, $notifiable);
});
}
}
Now Create EmailVerification With Markdown
php artisan make:mail EmailVerification --markdown=emails.verify-email
Edit The EmailVerrification as you want and the blade file
class EmailVerification extends Mailable
{
use Queueable, SerializesModels;
public $verifyUrl;
protected $user;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($url,$user)
{
$this->verifyUrl = $url;
$this->user = $user;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
$address = 'mymail#gmail.com';
$name = 'Name';
$subject = 'verify Email';
return $this->to($this->user)->subject($subject)->from($address, $name)->
markdown('emails.verify',['url' => $this->verifyUrl,'user' => $this->user]);
}
}
in the blade file change the design as you want and use verifyUrl to display the verification link and $user to display user information
thanks, happy coding :)
vendor\laravel\framework\src\Illuminate\Mail\resources\views\html
You will find the Laravel default email template in this file location.
If a notification supports being sent as an email, you should define a toMail method on the notification class. This method will receive a $notifiable entity and should return a Illuminate\Notifications\Messages\MailMessage instance. Mail messages may contain lines of text as well as a "call to action".
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$url = url('/invoice/'.$this->invoice->id);
return (new MailMessage)
->greeting('Hello!')
->line('One of your invoices has been paid!')
->action('View Invoice', $url)
->line('Thank you for using our application!');
}
You can use the laravel e-mail builder as documented here: https://laravel.com/docs/5.8/notifications#mail-notifications. Laravel will take care of the e-mail view.

Passing a collection to a mailable| Laravel 5.4

I am trying to get a mailable setup which has a collection of files. Mail controller looks like:
<?php
namespace App\Mail;
use App\Document;
use App\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;
class OrderComplete extends Mailable
{
use Queueable, SerializesModels;
public $user;
public $order;
public $documents;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct(User $user, Order $order, Document $document)
{
//
$this->user = $user;
$this->order = $order;
$this->documents = $document;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->markdown('emails.customers.complete');
}
}
Controller calling the mailable looks like;
use App\Document;
// other code...
$documents = Document::where('order_id', $orderId)
->where('product', 'like', '%response')
->get();
Mail::to($customer)
->send(new OrderComplete($customer, $order, $documents));
But I keep getting this error:
Type error: Argument 3 passed to App\Mail\OrderComplete::__construct() must be an instance of App\Document, instance of Illuminate\Database\Eloquent\Collection given, called in /Users/ap/sites/propair/app/Http/Controllers/OrderController.php on line 253
I'm pretty confused as I thought this should work?
thanks
This function declaration:
public function __construct(..., Document $document)
means PHP will enforce that $document is an instance of App\Document.
If you want to pass it a collection instead, you'll need to do:
public function __construct(..., \Illuminate\Database\Eloquent\Collection $documents)

Laravel pass object to view

When I'm trying to pass an object through a view with the AppServiceProvider it gives an error an says
Trying to get property of non-object
This is currently my App\Providers:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\User;
use Auth;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$users = Auth::user();
view()->share('user','users');
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
And when I say in the view:
{!! user->name !!}
It throws an error.
you are missing the '$' on users when passing the variable to view. So it can't be rendered on the view.
it must be:
$users = Auth::user();
view()->share('user', $users);

Resources