简体   繁体   中英

Laravel Server Side Event update global variable

I have an SSE event that selects last updates from table 'Newz' ad uses them to select from concerned tables the full data to stream it within the event. The problem is I start with a global '$lastrec' = 0 (last record id),and try to update it during event which unfortunately doesn't update. What am doing or gettin' wrong? Grateful for any light.

Here a ~snap of my tables:

### table NEWZ ###############
    id          |   mdl     |
    11          | Todo      |
    12          | Memo      |
    13          | Todo      |
    14          | Todo      |
    15          | Memo      |
              ...
### large table TODOS ###############
id          |       dtm     |       rqr     | subject   |   ... |
11          |   2022-08-01  |   John Doe    |   ...     |   ... |
13          |   2022-08-02  |   John Doe    |   ...     |   ... |
14          |   2022-08-04  |   John Doe    |   ...     |   ... |


### large table MEMOS ###############
id          |       dtm     |       DEST    | REF       |   ... |
12          |   2022-08-01  |   PROD.       |   ...     |   ... |
15          |   2022-08-04  |   PROD.       |   ...     |   ... |
                            ...

Here the Controller:

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Response;
class NewzController extends Controller
{
    private $lastrec =0;    //(last record id starts with 0)        
    

    public function getDataStream($lang){

        $response = new \Symfony\Component\HttpFoundation\StreamedResponse(function()  use ($lang){
            while(true) {
                $col=collect();
                
                $nwz = 'App\Models\Newz';
                $allnotif = $nwz::select('*')->where('id', '>' ,$this->lastrec)->get(); ///THIS IS THE PROBLEM $this->lastrec is always reset to 0 even after update
                
                foreach ($allnotif as $onenotif){ 
                    $mdl=$onenotif->mdl;                        
                    $zmodel = 'App\Models\\'.$mdl;
                    $notif = $zmodel::select('*')->where('id','=',$onenotif->id);
                    $col= $col->concat([$mdl => $notif]);
                    $this->lastrec = $onenotif->id;  // here I try to update $lastrec to last id value BUT unfortunately remains always 0
                }

                echo 'data: ' . json_encode(['lastrecord'=>$this->lastrec,'allNewz' => $col]). "\n\n"; //HERE I GET the right $lastrec but the start is always from 0       
                if( ob_get_level() > 0 ) ob_flush();
                flush();        
                if (connection_aborted()) { return;}                
                sleep(10);  
                
            }
            
        });
        $response->headers->set('Content-Type', 'text/event-stream');
        $response->headers->set('X-Accel-Buffering', 'no');
        $response->headers->set('Cach-Control', 'no-cache');
        return $response;

    }
}

How I can get the $lastrec to get dynamically updated according to the new records inserted.

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Response;
class NewzController extends Controller
{
    public function getDataStream($lang){

        $response = new \Symfony\Component\HttpFoundation\StreamedResponse(function()  use ($lang){
            while(true) {
                $col=collect();
                
                $nwz = 'App\Models\Newz';
                $allnotif = $nwz::select('*')->where('id', '>' ,$this->lastrec)->get(); 
                
                foreach ($allnotif as $onenotif){ 
                    $mdl=$onenotif->mdl;                        
                    $zmodel = 'App\Models\\'.$mdl;
                    $notif = $zmodel::select('*')->where('id','=',$onenotif->id);
                    $col= $col->concat([$mdl => $notif]);
                }
                $lastRecordId = $allnotif->last()->id;
                echo 'data: ' . json_encode(['lastrecord'=>$lastRecordId,'allNewz' => $col]). "\n\n";     
                if( ob_get_level() > 0 ) ob_flush();
                flush();        
                if (connection_aborted()) { return;}                
                sleep(10);  
                
            }
            
        });
        $response->headers->set('Content-Type', 'text/event-stream');
        $response->headers->set('X-Accel-Buffering', 'no');
        $response->headers->set('Cach-Control', 'no-cache');
        return $response;

    }
}

As a workaround solution:

the controller:

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Response;
class NewzController extends Controller
{
    //define the starting id ( $lastrec ) for $allnotifs in the route 
    //the user will set his own $lastrec

    public function getDataStream($lang,  $lastrec){

        $response = new \Symfony\Component\HttpFoundation\StreamedResponse(function()  use ($lang){
            while(true) {
                $col=collect();
                
                $nwz = 'App\Models\Newz';
                $allnotif = $nwz::select('*')->where('id', '>' ,$lastrec)->get(); 
                
                foreach ($allnotif as $onenotif){ 
                    $mdl=$onenotif->mdl;                        
                    $zmodel = 'App\Models\\'.$mdl;
                    $notif = $zmodel::select('*')->where('id','=',$onenotif->id);
                    $col= $col->concat([$mdl => $notif]);
                    $this->lastrec = $onenotif->id;  
                }

                echo 'data: ' . json_encode(['lastrecord'=>$this->lastrec,'allNewz' => $col]). "\n\n";        
                if( ob_get_level() > 0 ) ob_flush();
                flush();        
                if (connection_aborted()) { return;}                
                sleep(10);  
                
            }
            
        });
        $response->headers->set('Content-Type', 'text/event-stream');
        $response->headers->set('X-Accel-Buffering', 'no');
        $response->headers->set('Cach-Control', 'no-cache');
        return $response;

    }
}

The workaround happens in the js:

 var lastrec = storage.getItem('lastrec');
    //fire the streamEvent:
    lisTeningFunc(lastrec);

    const lisTeningFunc=async(last_save_did)=>{  
    if(typeof(EventSource) !== "undefined") {
      var source = new EventSource(the_Defined_Route_For_The_SSE+'/'+last_save_did);      
      source.addEventListener('message', event => {
        let alldata = JSON.parse(event.data);        
        if (alldata.lastrec > lastrec){ 
        lastrec = alldata.lastrec;
        // handleNewz(alldata.allNewz) /*do what you want with the newz*/
          //close the EventSource
           source.close()
          //fire a new one with the new lastrec
          lisTeningFunc(lastrec)
        }       
        }, false);
          source.addEventListener('error', event => {
            if (event.readyState == EventSource.CLOSED) {
                console.log('Event was closed');
            }
        }, false);
      } else {
        console.log("Sorry, your browser does not support server-sent events...");
      }
     }

So until someone suggest a solution to let the Laravel controller use a dynamic variable during SSE, the workaround solution is to reset the EventSource in the js-side and fire it again with the new lastrec.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM