Pusher on route not sending event in Laravel - laravel

I am creating a test app using Pusher for real-time notification on Laravel 4.
As I am testing the said API, I am having difficulties on making it work.
I have this on my routes.php:
Route::get('pusher-test', function(){
return View::make('pages.test');
});
Route::any('test', function(){
$pusher = new Pusher('key','sect','app_key'); //my keys are correct.
$pusher->trigger('notificationChannel', 'userRegistration', []);
});
Then my pusherTest.js file:
(function(){
var pusher = new Pusher('key');
var channel = pusher.subscribe('notificationChannel');
channel.bind('userRegistration', function(data){
$('.test').append('HEY!');
});
})();
My view page:
<html>
<head>
<meta charset="utf-8">
{{ HTML::style('_/css/bootstrap.css') }}
{{ HTML::style('_/css/mystyle.css') }}
</head>
<body>
<h2>HI!</h2>
<div class="test"></div>
{{ HTML::script('_/js/bootstrap.js') }}
{{ HTML::script('_/js/jquery.js') }}
{{ HTML::script('_/js/pusher/pusher.min.js')}}
{{ HTML::script('_/js/pusherTest.js')}}
</body>
</html>
When I try to observe the Debug Console of my app on Pusher.com,
here's what I see:
But when I hit the test route, it is not sending an event on my Pusher app, neither it sends the API message to my client. But if I will use the Create new Event tester on debug console, sure enough it sends the API message and my client receives and updates it.
What do you think is happening why on my route it can't send the event to my pusher app? I can't figure it out because is has no exception error. Please advice.

for me it was because I used the eu server and laravel is configured automatically on us server

To expand on #adutu's answer, you need to set
'cluster' => 'eu'
Inside the 'options' section of the Pusher driver configuration, in broadcasting.php.

There are three points at which you can debug your integration with Pusher:
Your interactions with Pusher's HTTP (REST) API
Ensuring events are being received by Pusher using the Pusher Debug Console
Ensuring your client integration is working by checking pusher-js logging
In your situation you've done 2. and you can see the events you are triggering aren't reaching the debug console. So, you need to do 1.
The Pusher PHP Server library provides details of how to enable debugging:
https://github.com/pusher/pusher-php-server#debugging
And how to get log information from the library:
https://github.com/pusher/pusher-php-server#logging
Once you have the pusher-php-server library logging information please feel free to post it so we can see what the problem may be e.g. are you getting a non 2xx response code?

The issue with this is due to the fact that you cannot set the host for the pusher broadcasting.
You only get this issue when you are using the EU cluster, in which case, you should change the host to:
api-eu.pusher.com
Similarly, you can make a custom broadcast driver. that does the same thing as the default one but sets the host parameter.
I am going to suggest an edit to the illuminate broadcast manager to make this change easier to make.

Related

How to properly connect Nuxt.js with a laravel backend?

I am starting a new project, Nuxt.js for the frontend and Laravel for the backend.
How can I connect the two?
I have installed a new Nuxt project using create-nuxt-app, and a new laravel project.
As far as I have searched, I figured I need some kind of environment variables.
In my nuxt project, I have added the dotenv package and placed a new .env file in the root of the nuxt project.
And added CORS to my laravel project, as I have been getting an error.
The variables inside are indeed accessible from the project, and im using them
like this:
APP_NAME=TestProjectName
API_URL=http://127.0.0.1:8000
And accessing it like this:
process.env.APP_NAME etc'
To make HTTP calls, I am using the official Axios module of nuxt.js, and to test it i used it in one of the components that came by default.
The backend:
Route::get('/', function () {
return "Hello from Laravel API";
});
and from inside the component:
console.log(process.env.API_URL)//Gives 127.0.0.1:8000
//But this gives undefined
this.$axios.$get(process.env.API_URL).then((response) => {
console.log(response);
});
}
What am I doing wrong here?
I have tried to describe my setup and problem as best as I can. If I overlooked something, please tell me and I will update my question. Thanks.
Taking for granted that visiting https://127.0.0.1:8000/ in your browser you get the expected response, lets see what might be wrong in the front end:
First you should make sure that axios module is initialized correctly. Your nuxt.config.js file should include the following
//inclusion of module
modules: [
'#nuxtjs/axios',
<other modules>,
],
//configuration of module
axios: {
baseURL: process.env.API_URL,
},
Keep in mind that depending on the component's lifecycle, your axios request may be occurring in the client side (after server side rendering), where the address 127.0.0.1 might be invalid. I would suggest that you avoid using 127.0.0.1 or localhost when defining api_uris, and prefer using your local network ip for local testing.
After configuring the axios module as above, you can make requests in your components using just relative api uris:
this.$axios.$get('/').then(response => {
console.log(response)
}).catch(err => {
console.error(err)
})
While testing if this works it is very helpful to open your browser's dev tools > network tab and check the state of the request. If you still don't get the response, the odds are that you'll have more info either from the catch section, or the request status from the dev tools.
Keep us updated!
Nuxt has a routing file stucture to make it easy to set up server side rendering but also to help with maintainability too. This can cause Laravel and Nuxt to fight over the routing, you will need to configure this to get it working correctly.
I'd suggest you use Laravel-Nuxt as a lot of these small problems are solved for you.
https://github.com/cretueusebiu/laravel-nuxt

laravel event dispatch from controller

Alright so I have been trying to set up a spreadsheet application with concurrent editing. I went down the laravel echo, redis, sockets route. (Any advice to just use pusher will be summarily dismissed). Now for the most part I have this working and I can call my event from tinker and see the data I want flow through redis to sockets and get picked up by my frontend. However the call simply does not work when placed in a controller; its like its just being ignored. For simplicity sake I removed all code from the controller function except for event(new SalesPricingReportEdit($request)); I can use this exact code in tinker storing the exact source of the request from dev tools {"change":[[0,"future contract price",null,750]],"customer_id":101443,"item_id":"MOFT0602-1-550"} and my ws responds on multiple instances of the page across different computers with the data attached to the WS. I can post any code anyone needs to help just let me know what you want to see.
EDIT(resolved): Alright so now that I am mostly finished with this project I have my write up I figured Id post it for posterity this is a process guide that lead me to successfully using laravel events with redis and socket-io via echo.
Register your new Event in laravel go to app/Providers/EventServiceProvider.php and put in the fully namespaced path for your Event that doesnt exist yet. Using the default namespace will save you a headache in implemntation but you can use a non-default
if you wish to gouge your own eyes out while you attempt to route the events on your frontend.
protected $listen = [ 'App\Events\EventName.php' => [
//you would put a handler here but for my case i was only dealing with an
//Event generated by server and handled by the client(browser)
//so it wasn't needed. KISS
],
Once you save that you just use the artisan generate event command and it will read the listener array and scaffold you up an event.
note: While we are in the providers folder lets just note the broadcastServiceProvider and its reference to the routes/channel file this isn't very important for me now but its good to remember
In your app/Events/EventName.php we will be configuring our event. Most of this is standard but there will be a few gotchas I dont want to forget about.
your class should by default implement ShouldBroadcast ... I changed this to shouldBroadcastNow as well as setting my default QUE_DRIVER=sync in global .env and config to sync .. this just avoids an extra overhead of queing the jobs..probably dumb in the long term but, for now queing is a bit overkill.
continue in app/Events/EventName.php
Next notice your construct function. To pass data through an event you need to declare a public variable in the class and set the value for that inside your constructor. By Default laravel will/should/suppposed to pass any public variable in the
class with the event.
public $change;
public function __construct($request){
$this->change = json_decode($request, true);
}
Next in your broadcastOn() function you want to return a new channel...essencially
return new [Type]Channel([channel-name]);
make sure you have all the facades you need in your header.
the broadcastWith() function will let you manipulate the data sent with the event.
I did not use the broadcastAs() function but, it is supposed to allow you to change the Event Name rather than using the default class name.
Now we are going to go to our controller file where we plan to actually fire the event from app/Http/Controllers/xxxxxxxxxController.php
use the syntax
event(new EventName($data))
when you want the event to get kicked off. this will not work as we have not set up redis or sockets but to test this is all in working order go to your .env and change the BROADCAST_DRIVER=log. once done wipe cache and do whatever it is you need to do to get the controller function to run(either by using tinker or by a frontend path you plan on using with the event). you should then be able to see the storage/app/logs/laravel.log contain the information from your event.
Go ahead and install redis on your server and use basic laravel configuration in .env and in config/database.php the only thing to change is to add in the .env BROADCAST_DRIVER=redis.
To avoid some complications go ahead and make sure your CACHE_DRIVER to file.
I have not yet set up multi connections with redis to let redis work both as broadcast and cache; ik its possible but I havent done it. so for now cache_driver can go away.
Also I tried to set this up using PHPredis but I admitted defeat and just used predis. Anyone that can figure this out I will venmo 50 bucks.
Finally to test that you have done this correctly go into
redis-cli > PING ...resp: PONG
Also you can use redis-cli monitor to verify that event data is indeed being pushed to redis.
Now we will start setup with npm we are going install laravel-echo-server, I will also get the pm2 package to act as my daemonizer for echo server.bash it up with
` #!/var/www/repoting/ bash
laravel-echo-server start`
then just run pm2 start socket.sh
when testing you might want to run laravel-echo-server start straight from the cli because the output stream will let you know when it observed an event broadcast in redis.
we will also need the
npm --save socket.io-client
or websockets don't work.
Lets go to resources/assets/js/bootstrap.js
import Echo from "laravel-echo";
window.io = require('socket.io-client');
if (typeof io !== 'undefined') {
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001',
});
}
This is initializing our websocket connection.
Now in our blade file we are going to subscribe to the channel and listen for events. Make sure to include the :6001/socket.io/socket.io.js file or your callbacks will fail
Why are we not doing this in the bootstrap.js you ask? because part of the channel name I am using is being passed by the controller with the view so to subscribe to the right channel I need something like
channel-name-{{$customer_id}}.
What you say I should have properly set up vue and done things the way they were designed to be done in vue....go home your drunk.
So now in resources/views/xxxxx.blade.php
I am using this in conjunction with handsontables so I am going to insert my listener in the afterRender hook.
Echo.channel('EventName-{{$customer_id}}')
.listen('EventName',function(data){
console.log(data);
});
any confusion here about what goes in the channel vs what goes in the listen clause can think of it as using the channelName and then the eventName by default the class name. There seems like in the past to have been some issues
with the class name being namespaced properly but I did not experience any problems.
this should all lead to seeing a console.log with your event data on any page subscribed to the the channel. But for prosperity sake here is the testing order to help verify each step along the way.
Troubleshooting steps
Is the event configured properly in laravel? Change the BROADCAST_DRIVER=log and verify you get a log entry when you run your controller.
Is the data actually being pushed to redis? with the right channel, etc? open redis-cli montior while you trigger an event and you should see feedback like "PUBLISH" "channel-name" "message"
Is echo server/socketio-server registering the event? look at your terminal that is running the laravel-echo-server start command you should see the event propagate from redis to echo there
Is your bootstrap.js file giving you an open web socket? go to dev-tools and check the network->ws if you see an entry click it and then on messages; make sure you see sent and recieved data. If you dont something is wrong in bootstrap.js
Is your clientside js retrieving data from the websocket event? if not you probably forgot to include you socket.io.js file.
Next Steps
-Implement whisper channels to notify the page of who is currently using the page as well as to unsubscribe the from the echo channel and remove any unneeded listeners
-pass handsontable selected data through the whisper channel and set those cells to readonly where the user is different from the current user
I ended up just adding the redis facade and calling Redis::publish(). My guess here is that I couldn't call an event without having a listener setup. I don't need a listener I just needed the event to fire and push it to redis. the real confusing part is why this works without a hitch in tinker and not in a controller is still a mystery but, I solved the immediate problem so this just gets chalked up to an edge case where I implemented something differently than it was probably designed to be.

Vuejs Axios POST request gets HTTP422 error from Laravel backend

Hi I am using Vuejs in the frontend and Laravel in the backend. The role of Laravel is handling the API only. The frontend and backend are separated, i.e. I am not using Vuejs in Laravel's resource/js folder.
Now I am sending Axios POST request from Vuejs to Laravel. All the form input values are prevalidated using HTML5 required attribute. And when I console.log the request data, it shows all the fields filled.
In Vue file:
const data = {
name: this.name,
gender: this.gender,
mobile_no: this.mobile_no,
image: this.userImage
};
console.log("Request data . . . .", data);
const response = await this.axios
.post(`${this.AppURL}/admin/user/create`, data, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(() => {
console.log("Success. . . . ")
alert("Successfully Driver Added");
})
.catch(error => console.log(error));
And in Laravel, the request is passed through some validation. It's a simple validation to check if all the fields are filled.
I am also using JWTAuth package for the authentication, and the token is generated by it.
It's too much code to write them all the way down here. But I am sure you can understand what I mean.
What I am getting as a response is this
POST http://localhost:8000/api/admin/user/create 422 (Unprocessable Entity)
The actual result I am expected to get is either success or some errors that is according to some if conditions in validation or token check.
I tried to figure out where this error might come from. What I think at the moment is this could be due to the absence of csrf_token in the POST request. As I'm sending the request outside Laravel, csrf_token is missing in the form. I am not 100% sure though about this.
So my question is:
How can I include csrf_token in Axios POST request, when I send it from outside Laravel.
If this 422 error is not related with csrf_token, what could be causing this? Any previos experiences like min? and any solutions for this?
Thanks in advance for your help.
Please, modified catch block as #Jack suggested:
.catch(error => {
console.log("ERRRR:: ",error.response.data);
});
Now you can get errors and handle errors in the catch block.
.catch(function (error) {
console.log(error.response.data.errors);
});
please use this code I hope it work's.
I was also facing the same issue, i think it is due to some Headers missing in your Api request from vue.js. here some tips which may helps you to solve this issues.
Make sure that you are protecting your Api Routes or not(by sanctum or something else). If you are protecting , then make make sure that you are sending authentications token in headers.
Second make sure that your request(axios or jwt) should contained valid data, if your are sending images or files etc make sure how can we send them.
First, get request and check in laravel by dd($erquest->all()); if you are geeting data then validate, it is possible that laravel request doesnt contained your sending data..
These errors may be caused due to follow reasons, ensure the following steps are followed.
To connect the local host with the local virtual machine(host).
Here, I'am connecting http://localhost:3001/ to the http://abc.test
Steps to be followed:
We have to allow CORS, placing Access-Control-Allow-Origin:* in header of request may not work. Install a google extension which enables a CORS request.
Make sure the credentials you provide in the request are valid.
Make sure the vagrant has been provisioned. Try vagrant up --provision
this make the localhost connect to db of the homestead.
Just click on the preview tab within network section in the dev tool, you are going to see the actual error message.

Laravel event not being Broadcast

I am working on a chat/message feature for an app. When a User sends a message, I want a specific Event to be triggered and to be broadcasted. I am then wanting Laravel Echo to listen on the event's broadcast channel to an event via Laravel Echo, using the pusher driver.
I am wanting the Laravel Echo implementation to be in a Vue component and to retrieve the data that was broadcasted via the event. Currently, I can't get an event to broadcast to either a private channel or just a channel.
Here is what I have done:
1) Added the config to .env.
2) Added config to bootstrap.js :
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'mykey',
encypted: false
});
3) Added auth check in App\Providers\BroadcastServiceProvider (just returning true if User is signed in for now):
Broadcast::channel('chat', function ($user) {
// verify that user is recipient of message
return \Auth::check();
});
4) Added App\Providers\BroadcastServiceProvider::class, to App/config/app.php.
5) Created the Event App\Events\UserSentMessage, which broadcasts on a PrivateChannel named chat. I have also tried to broadcast to a Channel. I checked and the event is being fired from a call to the event() helper in a controller, it just seems to not be broadcast. I have also tried using the broadcast method in the controller mentioned.
6) Added the following within the mounted Vue life cycle hook in a valid Vue component (component is rendering data etc as expected, just not working with Laravel Echo atm):
Echo.private('chat').listen('UserSentMessage', (data) => {
console.log(data);
}, (e) => {
console.log(e);
});
Have also tried:
Echo.channel('chat').listen('UserSentMessage', (data) => {
console.log(data);
}, (e) => {
console.log(e);
});
The Vue component is successfully subscribing to the channel specified. The pusher debug console recognized that it is being subscribed to, but the Event, when triggered never gets broadcasted.
Seems to be that there is a problem with broadcasting the event. I have also tried using the broadcast() helper, rather than the event() helper.
Also, when subscribing to the event with Laravel Echo via Echo.private(). It seems to prefix the channel name with private, so I have also tried broadcasting (in the event) to a channel named private-chat.
I can recommend You to check Your .env file and make sure BROADCAST_DRIVER is not log (try pusher) and also don't forget to keep running queue listener:
php artisan queue:listen
UPD.: if You look for more advanced solution, read about laravel horizon
the event will not be broadcasted immediately, it will be send to the queue, only when you listen or work on the queue, the event will be consumed. If you want execute jobs immediately, set QUEUE_DRIVER=sync . see: laravel queue
In my case, my event class file is generated by "make:event", it does have broadcastOn method... But have no implements ShouldBroadcast~
It causes the laravel-echo-server output nothing~
Laravel Framework 8.13.0
I have upvoted Num8er's reply but i also found some other issues so maybe they can help you too.
1) Remove all 'private-' from the beginning of your channel names. These get handled behind the scenes by the various libraries (eg socket.io/laravel-echo). If you look at any debug output you will see 'private-' prepended to the front of the channel names but you DO NOT need to add these.
2) If you're using redis then make sure the REDIS_PREFIX is set to an empty string in your .env file. By default it's set to something like 'laravel_database' and this messes up the channel names.
REDIS_PREFIX=
3) Make sure you've got your laravel-echo server running (and redis/pusher). Also you need to make sure you have the queue worker running:
php artisan queue:work
4) It's worth enabling debugging output on your Echo Server as this will tell you useful info about traffic (eg channel names) so modify the laravel-echo-server.json file (in your project root dir) so that devMode is set to true:
"devMode": true,
#materliu: that was a good hint. In my case i did not create a queue with the working directory set to the project i am working on. Using circus. The event was triggered in code but no job listener was available. As soon as i run "php artisan queue:listen" suddenly all previous broadcasts have been processed.
Usually its difficult to figure out which component of a complex system does not work.

How to debug AJAX (POST) with PhpStorm and Xdebug?

I have configured PhpStorm to debug HTTP GET - but only when I load a page directly.
When I want to debug AJAX, I take the URL which my JS would request and create a PhpStorm configuration to debug it.
Not particularly elegant, is it?
And, of course, I can't do that for POST requests (or can I?).
Ideally, I would like to load my AngularJs app in the browser (Chrome) and be able to breakpoint and debug the backend in PhpStorm.
I googled a lot, and found much that came close, but I can't find the answer :-(
Who can help?
[Update] a few years later, and I am using the excellent and free Postman to test both GET and POST.
If Xdebug and PHPStorm are configured to debug HTTP GET when loading a page normally, then simply include the GET parameter in the URL of the AJAX request in your Javascript. For example: http://example.com/script.php?XDEBUG_SESSION_START=PHPSTORM
Turn on Debug listening in PHPStorm, send the AJAX request with the new URL, and the debugger should catch it. The POST data you are looking for should appear in $_POST as usual.
I am using kind of hacking method to debug AJAX requests. My project is Laravel. You can change this code as compatible with your technology.
Basic idea is:
Grab home page debug port
Create a session
Using this session concatenate the AJAX url
When you start debugging, the port will be applied for all ajax urls which having + debug_url.
HomeController#index method
// Development purpose only
if ($request->has('XDEBUG_SESSION_START')) $request->session()->put('debug_port' , $request->get('XDEBUG_SESSION_START'));
master.blade.php
<script>
var debug_url='?XDEBUG_SESSION_START={{session('debug_port')}}';
</script>
submit.blade.php
<script>
$.ajax(url + debug_url, {
method:'post',
data:{}
});
</script>

Resources