Laravel 5.3 not sending Events to pusher - javascript

I'm using laravel 5.3 for my website. I needed to add real time functionality to my app so I used pusher. but the problem is when the event has been triggered nothing happened and no events sent to pusher.
my pusher configuration in broadcasting.php file :
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_KEY'),
'secret' => env('PUSHER_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => 'eu',
'encrypted'=>true
],
],
my event class:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ChatEvent implements ShouldBroadcast
{
use InteractsWithSockets, SerializesModels;
public $data;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
// return new PrivateChannel('test-channel');
return ['test-channel'];
}
and my pusher javascript code:
Pusher.logToConsole = true;
var pusher = new Pusher('pusher_id', {
cluster:'eu',
encrypted: true
});
var channel = pusher.subscribe('test-channel');
channel.bind('App\\Events\\ChatEvent', function(data) {
console.log(data);
alert(data);
});

Check your Pusher credentials in your .env file.
PUSHER_KEY should be PUSHER_APP_KEY
PUSHER_SECRET should be PUSHER_APP_SECRET

Related

Pusher: Callback function not executing with standalone Laravel (API) Vue.js(client) apps

Please I need help with pusher integration in my Laravel & Vue js project. NOT SPA (i.e separate Apps (Laravel - API & Vuejs- frontend)
The goal is to establish a real-time chat between two users.
The whole cycle is working perfectly well but the pusher callback is not executing, therefore making the chat function limited to the app API level only. It is not real-time which is why I'm integrating pusher to handle that.
Please see the code snippets below, ready to provide more on request. I've spent days on this, still can't figure out what I'm doing wrong.
Thanks in anticipation.
CommentController
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$user = Auth::user();
$validator = Validator::make($request->all(), [
'bid_id' => 'required',
'message' => ['required', 'string'],
]);
if ($validator->fails()) {
return response()->json(["error" => $validator->errors()], 400);
}
try {
$comment = $user->comments()->create([
'bid_id' => $request->bid_id,
'message' => $request->message,
]);
// Fire the comment broadcast event
// event(new CommentEvent($comment));
broadcast(new CommentEvent($user, $comment->load('user')))->toOthers();
} catch (Exception $exception) {
Log::error("Error while creating Comment" . $exception->getMessage());
} finally {
return response()->json(['comment' => $comment], 201);
}
}
CommentEvent.php
<?php
namespace App\Events;
use App\Models\Comment;
use App\Models\User;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CommentEvent implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #param $comment
*
* #return void
*/
public $user;
public $comment;
public function __construct(User $user, Comment $comment)
{
$this->user = $user;
$this->comment = $comment;
}
/**
* Get the channels the event should broadcast on.
*
* #return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new PresenceChannel('comment-channel');
}
public function broadcastAs()
{
return 'CommentEvent';
}
}
Main.js
import Pusher from "pusher-js";
/* -------------------------------------------------------------------------- */
/* PUSHER CONFIG */
/* -------------------------------------------------------------------------- */
Pusher.logToConsole = true;
let pusher = new Pusher(process.env.VUE_APP_PUSHER_APP_KEY,{
cluster: process.env.VUE_APP_PUSHER_APP_CLUSTER,
encrypted: false,
});
Vue.prototype.$pusher = pusher;
App.vue
<script>
export default {
name: "App",
components: {},
created() {
let channel = this.$pusher.subscribe("comment-channel");
channel.bind("pusher:subscription_succeeded", function(members) {
console.log(members);
console.log("succesfully subscribed!");
});
channel.bind("CommentEvent", function(data) {
console.log(data);
this.$store.commit("ADD_COMMENT", data.comment);
});
},
methods: {
},
};
</script>
I've been able to resolve this using.
but I had to switch tech. The real-time chat system of my app is now driven by socket.io, Redis and a simple node js server wrapped within the API
I'll be willing to help with code snippets if you need me to.

Laravel Redis display sock data with vue

I built a simple event class with laravel, which I fire if one sents a notifications the event class looks like this:
class InquirySent extends Event implements ShouldBroadcast
{
use SerializesModels;
public $inquiries;
public function __construct($inquiries)
{
$this->inquiries = $inquiries;
}
public function broadcastOn()
{
return ['inquiry-sent-channel'];
}
}
I fire the event (create a new instance) like this:
# fire inquiry notification event
event(new InquirySent(
$user->notifications()->where('type', InvoiceInquiry::class)->count()
));
I set up my node server with this script:
var server = require('http').Server();
var io = require('socket.io')(server);
// class declaration
var Redis = require('ioredis');
/**
* Redis UserSignedUp Channel
*/
var redisSignedUp = new Redis();
redisSignedUp.subscribe('signed-up-channel');
/**
* Redis InquirySent Channel
*/
var redisInquirySent = new Redis();
redisInquirySent.subscribe('inquiry-sent-channel');
redisInquirySent.on('message', function(channel, message) {
message = JSON.parse(message);
console.log(message.data.inquiries);
io.emit(channel + ':' + message.event, message.data.inquiries);
});
// run server on port X
server.listen(3000);
And in my event.js I bind it like this:
var socket = io('http://192.168.3.115:3000');
new Vue({
el: '#app',
data: {
inquiries: [],
},
ready: function() {
// InquirySent event
socket.on('inquiry-sent-channel:App\\Events\\InquirySent', function(data) {
console.log(data);
this.inquiries.push(data);
}.bind(this));
}
});
The console (command line) returns the correct value in my case: 69
but if I try to put it in my view with vue.js it does not display anything, nor do I get any errors in the browser console:
<li v-for="inquiry in inquiries">#{{ inquiry }}</li>

use laravel echo server in react native client

I want to use laravel echo server in react native app
but I think something is wrong that I don't know what is it
I get this error in my log
undefined is not an object (evaluating 'this.connector.channel')
channel
D:\react-native\taav\node_modules\laravel-echo\dist\echo.js:750:34
componentDidMount
it is my laravel
class updateStatus implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* Create a new event instance.
*
* #return void
*/
public $activity;
public function __construct( Activity $a)
{
//
$this->activity=$a;
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return ['channel'];
}
}
that I know my laravel server is correct because I can use correctly my socket in browser
and my react native code:
import React, {Component} from 'react';
import Echo from "laravel-echo"
import io from 'socket.io-client/dist/socket.io';
export default class Activities extends Component {
constructor(props) {
super(props)
this.btnadd = this.btnadd.bind(this)
this.SearchMethod = this.SearchMethod.bind(this)
this.socket = io('http://'.concat(server).concat(':6001'), {json: false})
}
componentDidMount() {
var echo = window.Echo = new Echo({
broadcaster: 'io',
host: 'http://'.concat(server).concat(':6001')
});
window.Echo.channel('channel')
.listen('updateStatus', (e) => {
// this.additem()
})
}
Try defining your broadcaster as 'socket.io' instead and that error should go away:
var echo = window.Echo = new Echo({
broadcaster: 'socket.io',
host: 'http://'.concat(server).concat(':6001')
});
Edit:
Looks like I'd also done some more magic with the echo library. From memory there was an issue getting the Echo library to pickup 'io' when it's imported here. What I ended up doing was copying the Echo code directly into my project and editing it to make it work. If you copy echo.js from /node_modules/laravel-echo/dist/echo.js into your own project and add this to the start of the file:
window.navigator.userAgent = 'react-native';
var io = require('socket.io-client');
and this to the end of the file:
export default Echo;
Then find the line of code that says
this.socket = io(this.options.host, {...this.options, ...{jsonp: false}});
and replace it with the following:
this.socket = io(this.options.host, this.options);
Then in your code above import Echo from this version in your project instead of from laravel-echo you'll hopefully have better luck. Sorry I didn't remember about that to start with!

Pusher notification with Laravel 5.4 not working as expected

So I'm really stuck for a while now, with Laravel event and pusher API.
I created event and broadcast, but when I access with pusher Javascript API it returns empty array, when I try to print it in the route it also returns empty array, meanwhile if I check Laravel log stoarage/logs/laravel.log I see exactly what I am expecting in the Javascript and route.
My code:
.env
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=******
PUSHER_APP_KEY=524**************8
PUSHER_APP_SECRET=d2**************c
Boadcasting.php
'default' => env('BROADCAST_DRIVER', 'pusher'),
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => 'us2',
'encrypted' => true
],
],
The event class: ProjectEvent.php
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ProjectEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $username;
public $message;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($username)
{
$this->username = $username;
$this->message = "{$username} sent you a message";
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return ['project-update'];
}
}
Route:
Route::get('/test', function () {
print_r(event(new App\Events\ProjectEvent('Michel')));
//return "Event has been sent!";
});
Route::get('/view', function () {
return view('testevent');
});
testevent.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="http://js.pusher.com/3.1/pusher.min.js"></script>
<script type="text/javascript">
Pusher.logToConsole = true;
var pusher = new Pusher('524************8', {
cluster: 'us2',
encrypted: true
});
var channel = pusher.subscribe('project-update');
channel.bind('App\\Events\\ProjectEvent', function(data) {
alert(data.message);
});
</script>
</body>
</html>
I really can't figure out where it all going wrong, since I am able to see the event in the log while the JS alert isn't working, also I try to dump the event on the route, it return empty array()

FOSUserBundle AJAX Login with Symfony2 (routing)

I'm trying to make the AJAX authentication work with FOSUserBundle.
I have created an Handler directory with a AuthenticationHandler class :
<?php
namespace BirdOffice\UserBundle\Handler;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
class AuthenticationHandler implements AuthenticationSuccessHandlerInterface, AuthenticationFailureHandlerInterface
{
private $router;
private $session;
/**
* Constructor
*
* #param RouterInterface $router
* #param Session $session
*/
public function __construct( RouterInterface $router, Session $session )
{
$this->router = $router;
$this->session = $session;
}
/**
* onAuthenticationSuccess
*
* #param Request $request
* #param TokenInterface $token
* #return Response
*/
public function onAuthenticationSuccess( Request $request, TokenInterface $token )
{
// if AJAX login
if ( $request->isXmlHttpRequest() ) {
$array = array( 'success' => true ); // data to return via JSON
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
// if form login
} else {
if ( $this->session->get('_security.main.target_path' ) ) {
$url = $this->session->get( '_security.main.target_path' );
} else {
$url = $this->router->generate( 'home_page' );
} // end if
return new RedirectResponse( $url );
}
}
/**
* onAuthenticationFailure
*
* #param Request $request
* #param AuthenticationException $exception
* #return Response
*/
public function onAuthenticationFailure( Request $request, AuthenticationException $exception )
{
// if AJAX login
if ( $request->isXmlHttpRequest() ) {
$array = array( 'success' => false, 'message' => $exception->getMessage() ); // data to return via JSON
$response = new Response( json_encode( $array ) );
$response->headers->set( 'Content-Type', 'application/json' );
return $response;
// if form login
} else {
// set authentication exception to session
$request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception);
return new RedirectResponse( $this->router->generate( 'login_route' ) );
}
}
}
I have created a login Javascript function :
function login() {
$.ajax({
type: "POST",
url: Routing.generate('check_login_ajax'),
dataType: 'json',
data: {
_username: $('#username').val(),
_password: $('#password').val(),
_remember_me: false,
_csrf_token: $('#_csrf_token').val()
}
}).done(function(data) {
console.log(data);
}).fail(function(data) {
console.log(data);
});
}
In my routingAjax.yml, I have added the following lines to override the FOSUserBundle security route :
check_login_ajax:
pattern: /check_login_ajax
defaults: { _controller: FOSUserBundle:Security:check }
requirements:
_method: POST
options:
expose: true
In my global security.yml file, I have added the check_path, success_handler and failure_handler parts :
firewalls:
main:
pattern: ^/
form_login:
login_path: fos_user_registration_register
check_path: check_login_ajax
success_handler: user.security.authentication_handler
failure_handler: user.security.authentication_handler
provider: fos_userbundle
csrf_provider: form.csrf_provider
logout:
path: fos_user_security_logout
target: /
anonymous: true
My first issue is : the AJAX return this message: "Invalid CSRF token." (but I send a good one generated in PHP, maybe I missed something doing it). Here is my PHP code for it :
<?php
$csrfProvider = $this->container->get('form.csrf_provider');
$csrfToken = $csrfProvider->generateCsrfToken('popUpUser');
?>
Second issue : my login page (not the AJAX one) is not working anymore because the orignal route of FOSUserBundle login has been overwritten.
PS : I have posted a message yesterday : FOSUserBundle (login / register) + AJAX + Symfony2 but I have badly explained my problem. Sorry by advance.
First Issue: You are sending an invalid CSRF token. In Symfony 2.3 you could generate it using {{ csrf_token('authenticate') }} inside the template's input's value.
Second issue: Do not overwrite the route, simply use the original route: fos_user_security_check.
In general: if you use an AuthenticationSuccessHandler extending Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler your method could look something like this:
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
if ($request->isXmlHttpRequest()) {
return new JsonResponse(array('success' => true));
}
return parent::onAuthenticationSuccess($request, $token);
}
Do something similar for an AuthenticationFailureHandler extending Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler.

Categories

Resources