php [cakephp:API组件和控制器]用于ajax请求和Server-Sent事件的Cake模块。 #cakephp

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php [cakephp:API组件和控制器]用于ajax请求和Server-Sent事件的Cake模块。 #cakephp相关的知识,希望对你有一定的参考价值。

<?php

// ApisController
namespace App\Controller\Api;

use App\Controller\AppUsersController;
use Cake\Event\Event;

class ApisController extends AppUsersController
{

  /**
   * Initialize method
   * Add loading components.
   */
  public function initialize() {
    parent::initialize();
    $this->loadComponent('Api');
  }

  /**
   * Response status
   * @param void
   * @return Cake\Http\Response (json)
   */
  public function status() {
    return $this->Api->printJsonResponse([
      'debug_mode' => DEBUG_MODE,
      'request'    => $this->request->url,
      'authority'  => $this->Auth->user(),
    ]);
  }

}


// HogeController (extends ApisController)
namespace App\Controller\Api;

use App\Controller\Api\ApisController;
use Cake\ORM\TableRegistry;
use Cake\Datasource\ConnectionManager; 

class QueuesController extends ApisController
{

  /** 
   * Pull method
   */
  public function pull() {
    if ($this->request->is('get')) { 
      $queues = $this->Queues->find()
        ->where([/* conditions */])
        ->toArray();
      return $this->Api->printJsonResponse($queues);
    }
  }

  /**
   * Fetch (server-push) method
   */
  public function fetch() {
    $this->Api->printFetchHeader();
    $connection = ConnectionManager::get('default');
    while (true) {
      $queues = $this->Queues->find()
        ->where(['is_fetched' => false]);
      if ($queues->count()) { /* State change event occurred. */
        try { /* Flagging to queues as fetched, then send event. */
          foreach ($queues as $queue) { /* Flagging loop. */
            $tmpQueue = $this->Queues->patchEntity($queue, ['is_fetched' => true]);
            if (!$this->Queues->save($tmpQueue)) throw new \Exception('Failed to save fetched records.');
          }
          $connection->commit();
          $this->Api->printFetchEvent($queues, 'push', WAIT);
        } catch (\Exception $e) { /* Print error and rollback. */
          $connection->rollback();
          $this->Api->printFetchEvent($e->getMessage(), 'error', WAIT);
        }
      } else {
        $this->Api->printFetchEvent('Polling is alive.', 'ping', WAIT);
      }
    }
  }

}


namespace App\Controller\Component;

use Cake\Controller\Component;
use Cake\Controller\ComponentRegistry;
use Cake\Network\Exception\BadRequestException;

/**
 * Application Api Component
 * Base component for application apis.
 */
class ApiComponent extends Component
{


  /** 
   * Properties
   * Set in initialize method.
   */ 
  public $controller;
  public $request;
  public $debug = 'Print in response on debug mode.';


  /**
   * Initialize method
   * @param array $config
   * @return void
   */
  public function initialize(array $config) {
    $this->controller = $this->_registry->getController();
    $this->request    = $this->controller->request;
  }
  
  
  /**
   * Startup method
   * - Set controller properties (view / response).
   * - Detection bad request without authority.
   * @param void
   * @return Cake\Http\Response (json) (on failure)
   */
  public function startup() {
    $this->controller->autoRender = false;
    $this->controller->response = $this->controller->response->withCharset(ENCODING);
    if ($this->request->action == 'fetch') { /* event-stream request */
      if (!$this->controller->Auth->user()) return $this->printError(403);
    } else { /* ajax push & pull request */
      $this->controller->response = $this->controller->response->withType('application/json');
      if ( /* remove this in debug by DHC REST Client */
        !$this->controller->Auth->user() || 
        !$this->controller->request->is('ajax') || 
        strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest'
      ) return $this->printError(403);
    }
  }


  /**
   * Print JSON Response
   * Set & Print response as JSON
   * @param array | null $results
   * @param int          $code
   * @param string       $message
   * @return Cake\Http\Response (json)
   */
  public function printJsonResponse(
    array  $results = null,
    int    $code    = null,
    string $message = null
  ) { /* Print response hash as JSON */
    if ($status = !empty($results)) {
      $code    ?? $code    = 200;
      $message ?? $message = 'Api is working.';
    } else {
      $code    ?? $code    = 404;
      $message ?? $message = 'Results not found.';
    }
    $response = [
      'status'  => $status,
      'code'    => $code,
      'message' => $message,
      'results' => $results,
    ];
    if (DEBUG_MODE) $response += ['debug' => $this->debug];
    $this->controller->response = $this->controller->response->withStringBody(json_encode(compact('response')));
    return $this->controller->response;
  }


  /** 
   * Print error
   * Print response as JSON for illegal access.
   * @param int $code
   * @param string $message
   */
  public function printError(int $code=500, string $message='') {
    if (empty($message)) $message = 'Failed to api access.';
    return $this->printJsonResponse(null, $code, $message);
  }
  

  /**
   * Methods for Server-Sent Events in $this->controller->fetch()
   * @see https://gist.github.com/a08b20aea47f509d8947e6bb63dcb9e3
   */
  public function printFetchHeader() {
    header("Content-Type: text/event-stream\n");
    header("Cache-Control: no-cache\n");
  }
  public function printFetchEvent($data, string $event='message', int $sleep=1) {
    $print = "event: ".$event."\n";
    if (is_array($data) || is_object($data)) {
      $print .= "data: ".json_encode($data)."\n\n";
    } else {
      $print .= "data: ".$data."\n\n";
    }
    echo $print;
    ob_flush();
    flush();
    session_write_close();  //important!
    sleep($sleep);
  }
  public function printFetchFlush(int $sleep=1) {
    ob_flush();
    flush();
    session_write_close();  //important!
    sleep($sleep);
  }


}

以上是关于php [cakephp:API组件和控制器]用于ajax请求和Server-Sent事件的Cake模块。 #cakephp的主要内容,如果未能解决你的问题,请参考以下文章

这个回调如何对 cakePHP 组件起作用?

从 url 中删除控制器名称不适用于 cakephp 中的多个控制器

CakePHP Auth 如何允许特定的控制器和动作

在CakePHP中创建全局变量的最佳方法是什么?

php 图像组件cakephp 3

cakePHP 从自定义数组构建一个选择框