I'm currently using ClankBundle in my Symfony2 app and need to implement the Push to an Existing Site feature mentioned in the Ratchet documentation. However, I found no clues on how to accomplish this functionality using ClankBundle !
I have successfully implemented the Topic Handler Setup from the ClankBundle documentation, but need a way to add support for ZeroMQ.
Could you please demonstrate (preferably with code) how would one use ZeroMQ with Clankbundle?
I've found a workaround that might be useful to you too.
In my setup I have Periodic service that needs to broadcast new information to topic and I have custom topic handler.
First off inject custom topic handler in periodic service and save all subscribed topics in topic handler, something like this:
public function onSubscribe(Conn $conn, $topic)
{
if (!array_key_exists($topic->getId(), self::$subscribedTopics)) {
self::$subscribedTopics[$topic->getId()] = $topic;
}
$topic->broadcast('connected');
}
public function getSubscribedTopics() {
return self::$subscribedTopics;
}
In periodic fetch those topics and broadcast on them:
public function tick()
{
$subscribedTopics = $this->topic->getSubscribedTopics();
foreach($subscribedTopics as $subscribedTopic) {
$subscribedTopic->broadcast('yey');
}
}
Related
I'm using Symfony 4.4 with Redis for the session.
I have some controllers and I wish to update the DB on back ground after to send a reply to user.
So I have written a code like this:
class GetCatController extends AbstractController
{
public function getCatController(LoggerInterface $logger, ManagerRegistry $doctrine, SessionInterface $session, ValidatorInterface $validator)
{
[...]
$replyToSend = new JsonResponse($reply, 200);
$replyToSend->send();
//My back ground activity like to do some query on the db.
[...]
return null;
}
But I have some problems about the sessions.
Is there a better way to create and run background activity sending before the reply to user?
There are two decent ways to do this.
If you are running PHP under php-fpm (not mod_php), you can dispatch & catch an event, kernel.terminate In Symfony pre-4.4, this is called PostResponseEvent (TerminateEvent from 4.4/5.0).
The better choice may be with Symfony Messenger. Here, you would create a message object, with all the information needed to perform the task, and send it to a background queue (Redis is supported as a queue). A worker then consumes that message, and does the task.
I have a slack notification class that sends a message inside our company slack account, in a specific channel, every time an user performs the activation process.
The system works, but it's manually tested and that's not cool.
The notification is sent by a listener attached to an UserHasBeenActivated event, the listener is the following:
public function handle(UserHasBeenActivated $event)
{
Notification::route("slack", config("services.slack.user.url"))
->notify(new UserActivated($event->user));
}
Pretty straight forward. The problem here is that the notification is on demand thus it's difficult to test... because there isn't any sort of documentation on how to test on demand notifications!
At the moment I'm stuck here:
public function it_sends_a_notification_when_an_user_is_activated()
{
Notification::fake();
$user = factory(User::class)->states("deleted")->create();
$user->activate();
Notification::assertSentTo(
$user,
UserActivated::class
);
}
Of course this test fails, the activate() method is what triggers the Event UserHasBeenActivated and sequentially all the listeners, and one of them sends the corresponding notification.
Do you know how to test on demand Notifications? Is there any hidden API that am I missing?
For the newcomers
Laravel introduces in v5.5.14 the ability to test anonymous notification by using the provided Notification::fake() system.
More about this new feature here: https://github.com/laravel/framework/pull/21379
I am using Cakephp Events and Event Source/Server Sent Events (http://www.w3schools.com/html/html5_serversentevents.asp) for live updates.
From all the controllers, I am emitting events like this :
class MyController extends AppController {
public function someAction() {
//........
$event = new CakeEvent('Controller.MyController.example', $this, array(
'data' => $someData
));
$this->getEventManager()->dispatch($event);
//.........
}
}
And added following line in Config/bootstrap.php :
require_once APP . 'Config' . DS . 'events.php';
And in Config/events.php
App::uses('CakeEventManager', 'Event');
App::uses('MyListener', 'Lib/Event');
// Global Listener
CakeEventManager::instance()->attach(new MyListener());
And in Lib/Event/MyListener.php
App::uses('CakeEventListener', 'Event');
class MyListener implements CakeEventListener {
public function implementedEvents() {
return array(
'Controller.MyController.example' => 'example',
);
}
public function example(CakeEvent $event) {
/*Do some optional manipulation with the $event->data,then send the data using event stream.
How can I call some another Controller to create event stream ?
(Should I create Event Stream here itself? If yes, how?)
I know how to create event stream in simple php :
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
echo "data: $someData\n\n";
flush();
*/
}
}
How can I create event stream?
PS : I'm using Cakephp events because of it allow me collect required data from different controllers at one place, and then from there, I could create Event Stream (server sent events). If there are any better options, please share.
I think this question is far to broad to be answered in a reasonable long text. So I would recommend you to read this question and the first two answers Server-sent events and php - what triggers events on the server? because it's similar and explains SSE very well.
If you understood SSE you'll realize you'll need a php process that keeps running on a loop. The code from the libSSE lib is more or less selfexplaining I think.
class YourEventHandler extends SSEEvent {
public function update(){
//Here's the place to send data
return 'Hello, world!';
}
public function check(){
//Here's the place to check when the data needs update
return true;
}
}
$sse = new SSE();//create a libSSE instance
$sse->addEventListener('event_name',new YourEventHandler());//register your event handler
$sse->start();//start the event loop
You could archive the same by implementing this using a CakePHP shell.
However, your app needs to send / update an event to the shell process. One way is to send it to a DB and check the DB table every X seconds for something new to send. This is not very performant but easy to archive.
Another solution is to have another listener that allows you to send an event from your php script to the look that then sends the event data to the subscriber (the http client). You can get this done more or less simple with http://socketo.me/.
Disclaimer: I haven't implemented SSE myself, but the above should do it, you now have the tools and direction. I've implemented Ratchet for fun and learning purpose before.
In the Magento Ecommerce System, there are three events that fire before the system is fully bootstrapped
resource_get_tablename
core_collection_abstract_load_before
core_collection_abstract_load_after
These events also fire after Magento has bootstrapped.
What's a safe and elegant (and maybe event Mage core team blessed) way to detect when Magento has fully bootstrapped so you may safely use these events?
If you attempt to use certain features in the pre-bootstrapped state, the entire request will 404. The best I've come up with (self-link for context) so far is something like this
class Packagename_Modulename_Model_Observer
{
public function observerMethod($observer)
{
$is_safe = true;
try
{
$store = Mage::app()->getSafeStore();
}
catch(Exception $e)
{
$is_safe = false;
}
if(!$is_safe)
{
return;
}
//if we're still here, we could initialize store object
//and should be well into router initialization
}
}
but that's a little unwieldy.
I don't think there is any event tailored for that.
You could add you own and file a pull request / Magento ticket to include a good one.
Until then I think the only way is to use one of the events you found and do some checks on how far Magento is initialized.
Did you try to get Mage::app()->getStores()? This might save you from the Exception catching.
I'm building a monitoring solution for logging PHP errors, uncaught exceptions and anything else the user wants to log to a database table. Kind of a replacement for the Monitoring solution in the commercial Zend Server.
I've written a Monitor class which extends Zend_Log and can handle all the mentioned cases.
My aim is to reduce configuration to one place, which would be the Bootstrap. At the moment I'm initializing the monitor like this:
protected function _initMonitor()
{
$config = Zend_Registry::get('config');
$monitorDb = Zend_Db::factory($config->resources->db->adapter, $config->resources->db->params);
$monitor = new Survey_Monitor(new Zend_Log_Writer_Db($monitorDb, 'logEntries'), $config->projectName);
$monitor->registerErrorHandler()->logExceptions();
}
The registerErrorHandler() method enables php error logging to the DB, the logExceptions() method is an extension and just sets a protected flag.
In the ErrorController errorAction I add the following lines:
//use the monitor to log exceptions, if enabled
$monitor = Zend_Registry::get('monitor');
if (TRUE == $monitor->loggingExceptions)
{
$monitor->log($errors->exception);
}
I would like to avoid adding code to the ErrorController though, I'd rather register a plugin dynamically. That would make integration into existing projects easier for the user.
Question: Can I register a controller plugin that uses the postDispatch hook and achieve the same effect? I don't understand what events trigger the errorAction, if there are multiple events at multiple stages of the circuit, would I need to use several hooks?
Register your plugin with stack index 101. Check for exceptions in response object on routeShutdown and postDispatch.
$response = $this->getResponse();
if ($response->isException()) {
$exceptions = $response->getException();
}
to check if exception was thrown inside error handler loop you must place dispatch() in a try-catch block
The accepted answer by Xerkus got me on the right track. I would like to add some more information about my solution, though.
I wrote a Controller Plugin which looks like that:
class Survey_Controller_Plugin_MonitorExceptions extends Zend_Controller_Plugin_Abstract
{
public function postDispatch(Zend_Controller_Request_Abstract $request)
{
$response = $this->getResponse();
$monitor = Zend_Registry::get('monitor');
if ($response->isException())
{
$monitor->log($response);
}
}
}
Note that you get an Array of Zend_Exception instances if you use $response->getException(). After I had understood that, I simply added a foreach loop to my logger method that writes each Exception to log separately.
Now almost everything works as expected. At the moment I still get two identical exceptions logged, which is not what I would expect. I'll have to look into that via another question on SO.