Laravel 5.8 : manage failed mail notifications from a queue - error-handling

I'm a little confused about the management of mail notifications failed from a queue.
I've created a mail notification class that I use to send a same notification to multiple users.
The process works well, but i'm trying to set up a management for the notifications that would fail (like sending a mail to the admin users to alert them about the failed notifications).
Here is the mail notification class :
class MyCustomMailNotification extends Notification implements
ShouldQueue {
use Queueable;
/**
* The number of times the job may be attempted.
*
* #var int
*/
public $tries = 3;
/**
* The number of seconds the job can run before timing out.
*
* #var int
*/
//public $timeout = 90;
/**
* Create a new notification instance.
*
* #return void
*/
public function __construct()
{
//
}
/**
* 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)
->subject('My Subject')
->greeting('My greeting')
->line('My mail body')
->salutation('My salutations');
}
/**
* Get the array representation of the notification.
*
* #param mixed $notifiable
* #return array
*/
public function toArray($notifiable)
{
return [
//
];
}
public function failed(Exception $e)
{
dd('Entered failed from MyCustomMailNotification : ' . $e));
}
}
I've set a listener "LogNotification" To reach the handle of notification event, with a specific instruction to generate a fail :
EventServiceProvider:
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
'Illuminate\Notifications\Events\NotificationSent' => [
'App\Listeners\LogNotification',
],
];
Listener:
namespace App\Listeners;
use Illuminate\Notifications\Events\NotificationSent; use
Illuminate\Queue\InteractsWithQueue; use
Illuminate\Contracts\Queue\ShouldQueue;
class LogNotification {
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* #param NotificationSent $event
* #return void
*/
public function handle(NotificationSent $event)
{
$result = 1/0;
}
}
The mailing is made in a controller like this:
$when = Carbon::now()->addSeconds(5);
foreach ($users as $user) {
$user->notify((new MyCustomMailNotification())->delay($when));
}
As in the failed function, I don't get any information of the notification that has failed, my question is:
How can I related a failure with the notification that has failed?
The goal is to be able to get the information of the user who has therefore not received his notification email.
Thanks for any help, idea or solution!

Well, that was so simple that I didn't see it...
As the failed function is inside the notification class, I can related to the notification simply with:
$this->id
And then of course get all the informations about the notification from model/table like user id (notifiable_id) and data field with custom informations.

Related

Laravel with Linkedin API error - ServiceFactory::createService() must be an instance of OAuth\Common\Storage\TokenStorageInterface

I'm using Laravel to develop my website, and I integrated the linkedin login to it, it works fine for like a few months. then suddenly, last week i received an error. I didn't change any code that has something to do with Linkedin API. I'm suspecting whether it has something to do with Linkedin itself.
here's what the error looks like:
If you are using this library to integrate Linkedin to your laravel project, there might be an issue right now with the update. you can simply fix the error in OAuth.php by replacing it with this code:
<?php namespace Artdarek\OAuth;
/**
* #author Dariusz Prząda <artdarek#gmail.com>
* #copyright Copyright (c) 2013
* #license http://www.opensource.org/licenses/mit-license.html MIT License
*/
use \Config;
use \URL;
use \OAuth\ServiceFactory;
use \OAuth\Common\Consumer\Credentials;
class OAuth {
/**
* #var ServiceFactory
*/
private $_serviceFactory;
/**
* Storege name from config
*
* #var string
*/
private $_storage_name = 'Session';
/**
* Client ID from config
*
* #var string
*/
private $_client_id;
/**
* Client secret from config
*
* #var string
*/
private $_client_secret;
/**
* Scope from config
*
* #var array
*/
private $_scope = [];
/**
* Constructor
*
* #param ServiceFactory $serviceFactory - (Dependency injection) If not provided, a ServiceFactory instance will be constructed.
*/
public function __construct(ServiceFactory $serviceFactory = null)
{
if (null === $serviceFactory)
{
// Create the service factory
$serviceFactory = new ServiceFactory();
}
$this->_serviceFactory = $serviceFactory;
}
/**
* Detect config and set data from it
*
* #param string $service
*/
public function setConfig($service)
{
// if config/oauth-4-laravel.php exists use this one
if (Config::get('oauth-5-laravel.consumers') != null)
{
$this->_storage_name = Config::get('oauth-5-laravel.storage', 'Session');
$this->_client_id = Config::get("oauth-5-laravel.consumers.$service.client_id");
$this->_client_secret = Config::get("oauth-5-laravel.consumers.$service.client_secret");
$this->_scope = Config::get("oauth-5-laravel.consumers.$service.scope", []);
// esle try to find config in packages configs
}
else
{
$this->_storage_name = Config::get('oauth-5-laravel::storage', 'Session');
$this->_client_id = Config::get("oauth-5-laravel::consumers.$service.client_id");
$this->_client_secret = Config::get("oauth-5-laravel::consumers.$service.client_secret");
$this->_scope = Config::get("oauth-5-laravel::consumers.$service.scope", []);
}
}
/**
* Create storage instance
*
* #param string $storageName
*
* #return OAuth\Common\\Storage
*/
public function createStorageInstance($storageName)
{
$storageClass = "\\OAuth\\Common\\Storage\\$storageName";
$storage = new $storageClass();
return $storage;
}
/**
* Set the http client object
*
* #param string $httpClientName
*
* #return void
*/
public function setHttpClient($httpClientName)
{
$httpClientClass = "\\OAuth\\Common\\Http\\Client\\$httpClientName";
$this->_serviceFactory->setHttpClient(new $httpClientClass());
}
/**
* #param string $service
* #param string $url
* #param array $scope
*
* #return \OAuth\Common\Service\AbstractService
*/
public function consumer($service, $url = null, $scope = null)
{
// get config
$this->setConfig($service);
// get storage object
$storage = $this->createStorageInstance($this->_storage_name);
// create credentials object
$credentials = new Credentials(
$this->_client_id,
$this->_client_secret,
$url ? : URL::current()
);
// check if scopes were provided
if (is_null($scope))
{
// get scope from config (default to empty array)
$scope = $this->_scope;
}
// return the service consumer object
return $this->_serviceFactory->createService($service, $credentials, $storage, $scope);
}
}

Get All Connected Users (Laravel 5)

How to display all connected users in my home?
This is a very basic, but hopefully an efective way to detect both Guest and Registered users on your Laravel5 application.
Step 1
Open the file config/session.php and change the driver to database.
Step 2
We need to create the sessions table, so use the following artisan command php artisan session:table to generate the migration file.
Step 3
On this newly generated migration, you need to add a new user_id column, this is so we can relate the session to a user, if that user is logged in of course.
Open the file migrations/xxxx_xx_xx_xxxxxx_create_session_table.php and add the following inside the Schema::create:
$t->integer('user_id')->nullable();
Here is how the full migration should look:
<?php
use Illuminate\Database\Migrations\Migration;
class CreateSessionTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('sessions', function($t)
{
$t->string('id')->unique();
$t->text('payload');
$t->integer('last_activity');
$t->integer('user_id')->nullable();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('sessions');
}
}
Step 4
Run composer dump-autoload and php artisan migrate.
Note: If you don't have Composer installed globally, just use php composer.phar dump-autoload.
Step 5
Save the Eloquent Model somewhere on your application as Session.php.
Note: The recommended place to save this is on the app directory.
Step 6
Now you just need to know how to use it.
.
.
.
Usage
Place the following Session::updateCurrent(); somewhere on your code, as this will make sure that the session entry for the current user get's updated, just an example, you can place it on your app/routes.php file.
Get all users (Guests + Registered)
$all = Session::all();
If you need to check all users online for a certain period, like 10 minutes, you need to call the activity(:limit) method, like so:
$all = Session::activity(10)->get();
Note: This method can be used in combination with the guests() and/or registered() methods.
Guest Users
Grab all
$guests = Session::guests()->get();
Get the # of Guest users
$total = Session::guests()->count();
Registered Users
Grab all
$registered = Session::registered()->get();
foreach ($registered as $online) {
// You can retrieve the user information using something like:
var_dump($online->user->email);
}
Get the # of Registered users
$total = Session::registered()->count();
Eloquent model:
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Session;
use Illuminate\Database\Eloquent\Builder;
use Cartalyst\Sentinel\Laravel\Facades\Sentinel;
class Session extends Model
{
/**
* {#inheritdoc}
*/
public $table = 'sessions';
/**
* {#inheritdoc}
*/
public $timestamps = false;
/**
* Returns the user that belongs to this entry.
*
* #return \Cartalyst\Sentinel\Users\EloquentUser
*/
public function user()
{
return $this->belongsTo('Cartalyst\Sentinel\Users\EloquentUser');
}
/**
* Returns all the users within the given activity.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #param int $limit
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeActivity($query, $limit = 10)
{
$lastActivity = strtotime(Carbon::now()->subMinutes($limit));
return $query->where('last_activity', '>=', $lastActivity);
}
/**
* Returns all the guest users.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeGuests(Builder $query)
{
return $query->whereNull('user_id');
}
/**
* Returns all the registered users.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeRegistered(Builder $query)
{
return $query->whereNotNull('user_id')->with('user');
}
/**
* Updates the session of the current user.
*
* #param \Illuminate\Database\Eloquent\Builder $query
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeUpdateCurrent(Builder $query)
{
$user = Sentinel::check();
return $query->where('id', Session::getId())->update([
'user_id' => $user ? $user->id : null
]);
}
}
Alternatively you can try this.

SMS Integration with Magento API

I am using Magento 1.8.1 and I want to integrate SMS with our store.
I have an API URL of SMS but don't know how and where to put that URL in Magento.
They provide me this code:
<?php
class sendsms
{
private $api_url;
private $time;
private $unicode;
private $working_key;
private $start;
private $sender_id;
public $api;
public $wk;
public $sid;
public $to;
/**function to set the working key
*
* #param string_type $wk:helps to change the working_key
*/
function setWorkingKey($wk)
{
$this->working_key=$wk;
}
/**function to set sender id
*
* #param string_type $sid:helps to change sender_id
*/
function setSenderId($sid)
{
$this->sender_id=$sid;
}
/**function to set API url
*
* #param string_type $apiurl:it is used to set api url
*/
function setapiurl($apiurl)
{ $this->api=$apiurl;
$a=strtolower(substr($apiurl,0,7));
if ($a=="http://") //checking if already contains http://
{
$api_url=substr($apiurl,7,strlen($apiurl));
$this->api_url=$api_url;
$this->start="http://";
}
elseif ($a=="https:/") //checking if already contains htps://
{
$api_url=substr($apiurl,8,strlen($apiurl));
$this->api_url=$api_url;
$this->start="https://";
}
else {
$this->api_url=$apiurl;
$this->start="http://";
}
}
/** function to intialize constructor
*
* #param string_type $wk: it is working_key
* #param string_type $sd: it is sender_id
* #param string_type $apiurl: it is api_url
* used for intializing the parameter
*/
function __construct($apiurl,$wk,$sd)
{
$this->setWorkingKey($wk);
$this->setSenderId($sd);
$this->setapiurl($apiurl);
}
/**
* function to send sms
*
*/
function send_sms($to,$message,$dlr_url,$type="xml")
{
$this->process_sms($to,$message,$dlr_url,$type="xml",$time="null",$unicode="null");
}
/**
* function to schedule sms
*
*/
function schedule_sms($to,$message,$dlr_url,$type="xml",$time)
{
$this->process_sms($to,$message,$dlr_url,$type="xml",$time,$unicode='');
}
/**
* function to send unicode message
*/
function unicode_sms($to,$message,$dlr_url,$type="xml",$unicode)
{
$this->process_sms($to,$message,$dlr_url,$type="xml",$time='',$unicode);
}
/**
* function to send out sms
* #param string_type $to : is mobile number where message needs to be send
* #param string_type $message :it is message content
* #param string_type $dlr_url: it is used for delivering report to client
* #param string_type $type: type in which report is delivered
* #return output $this->api=$apiurl;
*/
function process_sms($to,$message,$dlr_url="",$type="xml",$time='',$unicode='')
{
$message=urlencode($message);
$this->to=$to;
$to=substr($to,-10) ;
$arrayto=array("9", "8" ,"7");
$to_check=substr($to,0,1);
if(in_array($to_check, $arrayto))
$this->to=$to;
else echo "invalid number";
if($time=='null')
$time='';
else
$time="&time=$time";
if($unicode=='null')
$unicode='';
else
$unicode="&unicode=$unicode";
$url="$this->start$this->api_url/web2sms.php?workingkey=$this->working_key&sender=$this->sender_id&to=$to&message=$message&type=$type&dlr_url=$dlr_url$time$unicode";
$this->execute($url);
}
/**
* function to check message delivery status
* string_type $mid : it is message id
*/
function messagedelivery_status($mid)
{
$url="$this->start$this->api_url/status.php?workingkey=$this->working_key&messageid=$mid";
$this->execute($url);
}
/**
* function to check group message delivery
* string_type $gid: it is group id
*/
function groupdelivery_status($gid)
{
$url="$this->start$this->api_url/groupstatus.php?workingkey=$this->working_key&messagegid=$gid";
$this->execute($url);
}
/**
* function to request to clent url
*/
function execute($url)
{
$ch=curl_init();
// curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$output=curl_exec($ch);
curl_close($ch);
echo $output;
return $output;
}
}
I am new to Magento, so please help me with the API integration.
For SMS Integration you need to decide what event you want to handle.
Magento Events List are available here.
After it you need to create observer for choosen event.
An Observer is an event handler. It listens to any event it is attached to and accordingly reacts to the event.
Your SMS API should be usen in observer. ( It is method in PHP class. )
For creating observer in Magento you need to read this documentation.

Laravel Auth Custom Driver Error

FYI : I'm very new to Laravel and doing my best to learn it properly.
Working on an auth driver that uses a soap service to authenticate.
Error I get when trying to test with Auth::attempt()
Symfony \ Component \ Debug \ Exception \ FatalErrorException (E_COMPILE_ERROR)
Declaration of Project\Providers\AuthUserProvider::retrieveByToken() must be compatible with Illuminate\Auth\UserProviderInterface::retrieveByToken($identifier, $token)
Here is the driver...
<?php namespace Project\Providers;
use Illuminate\Auth\UserProviderInterface;
use Illuminate\Auth\GenericUser;
use Illuminate\Auth\UserInterface;
class AuthUserProvider implements UserProviderInterface {
/**
* External webservice for authentication
*/
private $webservice;
/**
* The user object.
*/
private $user;
/**
* Constructor
*
* #return void
*/
public function __construct(\Project\Webservice\AuthCheckApi $webservice)
{
$this->webservice = $webservice;
$this->user = null;
}
/**
* Retrieves a user by id
*
* #param int $identifier
* #return mixed null|array
*/
public function retrieveByID($identifier)
{
$this->user = is_null($this->user) ? $this->webservice->find($identifier) : $this->user;
return $this->user;
}
/**
* Tries to find a user based on the credentials passed.
*
* #param array $crendtials username|password
* #return mixed bool|UserInterface
*/
public function retrieveByCredentials(array $credentials)
{
if(!$user = $this->webservice->byusername($credentials['username'],$credentials['password'])) return false;
return new GenericUser($user);
}
/**
* Validates the credentials passed to the ones in webservice.
*
* #param UserInterface $user
* #param array $credentials
* #return bool
*/
public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
{
$validated = $this->webservice->validateCredentials($user,$credentials['username']);
return true;
}
/**
* Needed by Laravel 4.1.26 and above
*/
public function retrieveByToken()
{
return true;
}
/**
* Needed by Laravel 4.1.26 and above
*/
public function updateRememberToken()
{
return false;
}
}
Thanks for any help.
You are implementing the UserProviderInterface so you need to add the complete definition of all functions of the interface, here you are forgetting the arguments for the last two function
public function retrieveByToken($identifier, $token)
{
}
public function updateRememberToken($user, $token)
{
}

Symfony2-Doctrine: ManyToMany bi-directionnal relation

I've already search a lot befors asking, even the related topic Symfony2-Doctrine: ManyToMany relation is not saved to database
but still no answer.
I've got this two classes:
class Intervenant extends User
{
/**
* #ManyToMany(targetEntity="iMDEO\DISAASBundle\Entity\Domaine", inversedBy="intervenants", cascade={"persist","merge"})
*/
private $domaines;
/**
* Add domaines
*
* #param Domaine $domaines
*/
public function addDomaine(Domaine $domaines)
{
$this->domaines[] = $domaines;
}
/**
* Get domaines
*
* #return Doctrine\Common\Collections\Collection
*/
public function getDomaines()
{
return $this->domaines;
}
}
class Domaine
{
// ...
/**
* #ORM\ManyToMany(targetEntity="Intervenant", mappedBy="domaines", cascade={"persist","merge"})
*
*/
private $intervenants;
/**
* Add intervenants
*
* #param Intervenant $intervenants
*/
public function addIntervenant(Intervenant $intervenants)
{
$intervenants->addDomaine($this);
$this->intervenants[] = $intervenants;
}
/**
* Get intervenants
*
* #return Doctrine\Common\Collections\Collection
*/
public function getIntervenants()
{
return $this->intervenants;
}
}
When I save an Intervenant, everthing is OK.
But when i save the inverse side Domaine, the changes are not persisted.
Reading Symfony's doc and topics everywhere, I can't find any solution to get a bi-directionnal relation between my two entities.
Here's part of my DomaineController:
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('myBundle:Domaine')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Domaine entity.');
}
$editForm = $this->createForm(new DomaineType(), $entity);
$deleteForm = $this->createDeleteForm($id);
$request = $this->getRequest();
$editForm->bindRequest($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
return $this->indexAction();
}
// ...
My purpose is that when I create/edit an Intervenant, I can choose related Domaine.
And when I create/edit a Domaine, I link every Intervenants in it.
Could you please help me?