Laravel notification sent with no content and wrong subject - laravel

I've created this notification in app/Notifications:
class StatisticsExportNotification extends Notification implements ShouldQueue
{
use Queueable;
use EmailNotificationViewHTMLTrait;
protected $links;
/**
* Create a new notification instance.
*
*/
public function __construct($links)
{
$this->links = $links;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return [
MailChannel::class
];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
list($subject, $viewData) = $this->getNotificationViewHTML('statistics_export', $notifiable, ['links' => $this->links]);
return (new MailMessage())
->subject($subject)
->view('mail.main', compact('viewData'));
}
}
I'm trying to send it like this:
$member->notify(
new StatisticsExportNotification('testing')
);
Right now, the content of the email HTML template is just:
{{links}}
But I have confirmed that the same issue occurs if the HTML is just a hardcoded string and if I don't try to pass any variables to it.
That issue being, it seems to me that the toMail method is somehow not being called at all here. When I do logger()->debug($links) inside the class constructor, it logs the value of the variable. But when I do logger()->debug('test') inside toMail(), it doesn't log anything!
If I hardcode the subject and content inside the method, it makes no difference:
public function toMail($notifiable)
{
$subject = "foo";
$viewData = ["test" => "bar"];
return (new MailMessage())
->subject($subject)
->view('mail.main', compact('viewData'));
}
Whatever I do, the system sends the notification to the member's email, but the subject is "Statistics Export Notification" and the email body is empty!
What getNotificationViewHTML does is get the template of the message and populate it with the data we pass to it, but again, this code seems to never come into play at all. I've tried adding logging inside that method as well, and even putting in code that I know would throw an error if executed, but whatever I do, the notification sends with the same default subject and the same empty body.

I tried to recreate your Issue, and I think I did somehow, but I can never be sure 100% until you test it yourself. So Here is some advices :
1- While testing, try using direct array instead of compact to convert it
public function toMail($notifiable)
{
$subject = "foo";
$viewData = ["links" => "Here is the Links"];
return (new MailMessage())
->subject($subject)
->view('mail.main', $viewData);
}
2- In your mail.main view file, the correct syntax should embrace the variable name with $ :
{{ $links }}
and not just
{{ links }}
3- Probably your real issue there, MAKE SURE your view file has .blade.php so that Blade is allowed to parse codes like #section, #yield, {{$links}}, etc. Your mail view filename should be :
views/mail/main.blade.php
4- DO NOT FORGET TO RESTART QUEUE Codes after changing any codes from Statistics Notification file. And this should set the $subject successfully :
php artisan queue:restart
and after start it again
php artisan queue:work --tries=3

Try swapping out your via method with an array of strings:
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}

Does the definition of getNotificationViewHTML return an array [subject, html]?
The list keyword unpacks an array's elements, starting with the 0th element. Since you say the subject and content are wrong, my money is on the return value of getNotificationViewHTML.
To test, just hardcode getNotificationViewHTML like this:
public function getNotificationViewHTML()
{
return ["This Is the Subject", "<h1>This is My Message</h1>"];
}
If your mail then comes through with those values, you need to tailor your getNotificationViewHTML return value to match the example's format.

Related

Laravel | Problem send email with variables

I have a problem send email with variables.
I recived this error:
$login is undefined
view loginsucesso.blade.php
<p>Foi efetuado login na plataforma. {{ $login['nome'] }}</p>
Controller:
$login = array (
'nome' => "NAME TESTE"
);
Mail::to($request->email)->send(new emailteste($login));
Mail/emailteste:
class EmailTeste extends Mailable
{
use Queueable, SerializesModels;
public $login;
/**
* Create a new message instance.
*
* #return void
*/
public function __construct($login)
{
$this->login = $login;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this
->subject('Plataforma - Acesso efetuado com sucesso ')
->view('email/loginsucesso')
->with(['login'=>$this->login]);
}
}
I try pass array $login to view and recive error $login is undefined
Thanks!
From the docs;
Typically, you will still pass data via the mailable class' constructor; however, you should set this data to protected or private properties so the data is not automatically made available to the template. Then, when calling the with method, pass an array of data that you wish to make available to the template:
So I think your public property is conflicting with the data passed to the view. Do one or the other, not both.

Passing data to notification in laravel

Been stumped for awhile on how to pass two variables into a notification and have that notification include an action that contains a route with a token. The use case is that my application allows users (called advisors here) to give access to other users. If the added users are not already registered, their accounts will be created and they will receive an email with a token to complete their registration.
I have the following in my AddAdvisorsController:
else {
$newadvisor = Advisor::create($data);
$newadvisor->save();
$newadvisorID = $newadvisor->id;
$newAdvisorEmail = $newadvisor->email;
//create a token
$token = Str::random(60);
//email advisor and pass $token variable to notification
$newadvisor->notify(new NewAdvisorNotification($token, $newAdvisorEmail));
I have the following in my NewAdvisorNotification:
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class NewAdvisorNotification extends Notification
{
use Queueable;
public $token;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($token, $newAdvisorEmail)
{
//
$this->token = $token;
$this->newAdvisorEmail = $newAdvisorEmail;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->line('You are receiving this email because we received a new account request for your email.')
->action('Notification Action', route('new.advisor', [$this->token, $this->newAdvisorEmail]))
// ->action('Notification Action', route('advisor/new-account/{{ $token }}/{newAdvisorEmail}'))
->line('If you did not request a password reset, no further action is required.');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
}
The new user is getting created properly in the database, but I get an error saying:
Missing required parameters for [Route: update.advisor] [URI: advisor/new-account/{token}/{newAdvisorEmail}]. (View: C:\xampp\htdocs\HealthHub\resources\views\auth\new-accounts\advisor-new-account.blade.php)
I have the following routes:
Route::get('/advisor/new-account/{token}/{newAdvisorEmail}', 'NewAdvisorController#showNewAccountForm')->name('new.advisor');
Route::post('/advisor/new-account/{token}/{newAdvisorEmail}', 'NewAdvisorController#updateNewAccount')->name('update.advisor');
});
I think my code is having errors with this line:
->action('Notification Action', route('new.advisor', [$this->token, $this->newAdvisorEmail]))
However, I am not sure how to fix it
You error clearly states you are missing parameters for your route. The way to specify route parameters is by name, so declare an associate array with the route parameter name as the key.
->action('Notification Action', route('new.advisor', ['token' => $this->token, 'newAdvisorEmail' => $this->newAdvisorEmail,]))

Notification don't work on queue but work as Direct

i have a issue with notifications on laravel, if i send a notification directly without a queue this work as well
this notifiction needs send a email and save in database
i use this to call notify as exemple
$user = \App\User::find(1);
$candidato = \App\CandidatoVaga::where('id_user','=','1')->first();
$user->notify(new \App\Notifications\ConviteVagaCandidato($candidato));
And this is \App\Notifications\ConviteVagaCandidato
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
class ConviteVagaCandidato extends Notification implements ShouldQueue
{
use Queueable;
protected $CandidatoVaga;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct(\App\CandidatoVaga $CandidatoVaga)
{
$this->CandidatoVaga = $CandidatoVaga;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return ['database','mail'];
}
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
* #return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
return (new MailMessage)
->greeting('Olá, '.$this->CandidatoVaga->user->DadosPessoais->nome)
->subject('Convite')
->markdown('email.convite_selecao');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
'id_vaga' => $this->CandidatoVaga->id_vaga,
'id_user' => $this->CandidatoVaga->id_user,
'mensagem' => 'Você foi pré selecionado para a vaga',
'tipo' => 'Nova Vaga',
];
}
}
This return a sql error SQLSTATE[42601]: Syntax error: 7 ERRO
but without implements ShouldQueue works as well
One of the differences between the sync queue driver and a real queue driver is how the queued job handles stored Models.
Since the sync queue driver is processing the jobs directly in the same process, there is no extra work being done. If you build your Notification with a Model, it uses that exact model instance.
However, when using a real queue, Laravel has to serialize the data stored on the notification for the queue worker to handle it. Because models cannot be serialized easily, what it actually does is just store the model key on the notification, and then when the queue worker processes that job, it re-retrieves that model from the database using the stored key.
Based on the query you mentioned in the comments, it looks to me like your \App\CandidatoVaga model does not have a primary key ($primaryKey is empty). Because of this, there is no primary key field to query ("candidatos_vaga".""), and there is no primary key value stored (is null).
I see you've already come up with a solution for yourself. If, however, you still wanted to attempt to just use the model, you can try this:
Override the getQueueableId() method on your model. By default, this returns the primary key field. But, since you don't have one defined, you would need to override this method to provide some unique data that can be used to find your record again.
Override the newQueryForRestoration() method on your model. By default, this builds a query using the primary key field. But, since you don't have one defined, you would need to override this method to generate a query using the data generated by the getQueueableId() method.
NB: this is untested. I have never done this; this is just what I see looking through the source code.
I was able to solve it in a palliative way
public $id_vaga;
public $id_user;
public $nome;
public $titulo_vaga;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct($CandidatoVaga)
{
$this->id_vaga = $CandidatoVaga->id_vaga;
$this->id_user = $CandidatoVaga->id_user;
$this->nome = $CandidatoVaga->user->DadosPessoais->nome;
$this->titulo_vaga = $CandidatoVaga->vaga->titulo_vaga;
}

Upgrading from Laravel 4.2 to Laravel 5 - Container

I still have some trouble understanding all the changes from Laravel 4.2 to 5.0.
I have already managed to import all my models, controllers, config etc. I have namespaced almost everything but one thing that I can't seem to manage is to transform this code from 4.2 app\filters.php to my new 5.0 application.
Here's part of the code with some added explanations below that I'm having problems with. The following code was added so that we can conveniently ask for the permissions inside a group for all the actions/visible fields for the current user.
if(App::make('Authflag', $usergroup->id)->can(GroupPermissions::EDIT_MEMBERS)) ...
Code from 4.2:
App::before(function($request) {
App::instance('Authflags', array());
App::bind('Authflag', function($app, $param) {
$authflags = App::make('Authflags');
if(isset($authflags[$param]))
{
return $authflags[$param];
}
// Calculate generate flag value
$authflags[$param] = $authflag;
App::instance('Authflags', $authflags);
return $authflag;
});
});
Explanation:
instance Authflags contains group_id => permissionObject
Code explanation:
Get the Authflags array instance
If we already have the needed permissionObject return it
Else generate/calculate/request the permissionObject
Update the Authflags instance
Return the created permissionObject
But whatever I try I keep getting the ReflectionException in Container.php line 776: Class Authflag does not exist.
I tried to create a contract and a service and set a binding inside the AppServiceProvider. But I'm pretty sure I was doing a completely wrong/different thing.
I tried to just copy this code with some modifications inside the AppServiceProvder. But It just seemed wrong and didn't work.
(Come to think of it the whole code should have probably been inside the start/global.php)
How can I port this code to Laravel 5.0?
You have to use a middleware "encapsulation". Here is an example, that will show where you would have to put your custom before and after parts of your app.
use Closure;
class ChangeCookieLifetime {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
//anything put here will be run BEFORE your app
$response = $next($request);
//anything put here will be run AFTER your app
return $response
}
}
In your particular case iw dould like this:
use Closure;
class ChangeCookieLifetime {
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
App::instance('Authflags', array());
App::bind('Authflag', function($app, $param) {
$authflags = App::make('Authflags');
if(isset($authflags[$param]))
{
return $authflags[$param];
}
// Calculate generate flag value
$authflags[$param] = $authflag;
App::instance('Authflags', $authflags);
return $authflag;
});
$response = $next($request);
//anything put here will be run AFTER your app
return $response
}
}
Although I can't promise that the parts I inserted will work, this is the direct "translation" from Laravel 4.2 to Laravel 5

How to extend the Symfony2 Debug Toolbar with custom data?

I want to extend the Symfony2 Debug Toolbar with my own custom data.
I have a service where I want to log specific method calls and then display them in the web debug toolbar.
I read the cookbook article, but it's not very helpful.
I created my own DataCollector class:
class PermissionDataCollector extends DataCollector
{
private $permissionCalls = array();
private $permissionExtension;
public function __construct(PermissionExtension $permissionExtension)
{
$this->permissionExtension = $permissionExtension;
}
/**
* Collects data for the given Request and Response.
*
* #param Request $request A Request instance
* #param Response $response A Response instance
* #param \Exception $exception An Exception instance
*
* #api
*/
public function collect(Request $request, Response $response, \Exception $exception = null)
{
$this->permissionCalls = $this->permissionExtension->getPermissionCalls();
$this->data = array(
'calls' => $this->permissionCalls
);
}
public function getPermissionCallsCount()
{
return count($this->permissionCalls);
}
public function getFailedPermissionCallsCount()
{
return count(array_filter($this->permissionCalls, array(&$this, "filterForFailedPermissionCalls")));
}
private function filterForFailedPermissionCalls($var)
{
return $var['success'];
}
/**
* Returns the name of the collector.
*
* #return string The collector name
*
* #api
*/
public function getName()
{
return 'permission';
}
}
The PermissionExtension logs all calls and then I want to retrieve this array of calls in
PermissionDataCollector.
And a template just outputting {{ collector.permissionCallsCount }}.
The section gets displayed in the in the toolbar but it just shows a 0 which is wrong.
I'm not sure if I'm even doing this right, because the documentation lacks this section. I'm using Symfony 2.1
Has anybody extended the toolbar with custom data?
ah great! It works. I basically need to refer to $this->data all the time.
The reason for this that ->data is used by the Symfony\Component\HttpKernel\DataCollector\DataCollector and serialized (see DataCollector::serialize).
This is later stored (somehow, I don't know where, but it is later unserialized). If you use own properties the DataCollector::unserialize just prunes your data.
See https://symfony.com/doc/current/profiler/data_collector.html#creating-a-custom-data-collector
As the profiler serializes data collector instances, you should not store objects that cannot be serialized (like PDO objects) or you need to provide your own serialize() method.
Just use $this->data all the time, or implement your own \Serializable serializing.

Resources