Yii 2 에서 Restful API 원리 실례 분석

11858 단어 Yii2RestfulAPI
본 논문 의 사례 는 Yii 2 에서 Restful API 원 리 를 분석 했다.여러분 께 참고 하도록 공유 하 겠 습 니 다.구체 적 으로 는 다음 과 같 습 니 다.
Yii 2 는 Restful API 에 대한 기본 지원 이 중요 한 기능 이 있 습 니 다.짧 은 몇 개의 설정 을 통 해 기 존 모델 에 대한 RESTful API 를 간단하게 실현 할 수 있 습 니 다.
여기 서 rest 부분 소스 코드 를 분석 함으로써 yii 2 가 restful 을 실현 하 는 원 리 를 간단하게 분석 하고 일부 맞 춤 형 제작 을 통 해 관련 모델 에 대한 RESTful api 작업 을 실현 한다.
~대표 extends from 의 관계
| | rest/
| | |-Action.php ~ `\yii\base\Action`
| | |-Controller.php ~  `\yii\web\Controller`
| | | |-ActiveController.php ~ `rest\Controller`
| | |-Serializer.php ~ `yii\base\Component`
| | |-UrlRule.php ~ `yii\web\CompositeUrlRule`
| | |-CreateAction.php ~ `rest\Action`
| | |-DeleteAction.php ~ `rest\Action`
| | |-IndexAction.php ~ `rest\Action`
| | |-OptionsAction.php ~ `rest\Action`
| | |-UpdateAction.php ~ `rest\Action`
| | |-ViewAction.php ~ `rest\Action`
1. rest/Controller ~ \yii\web\Controller
Controller 는 RESTful API 컨트롤 러 류 의 기본 클래스 입 니 다.
이것 은 API 가 요청 한 제어 주기 에서 다음 단계 1~5 를 한 번 에 실현 합 니 다.
① 응답 내용 형식 분석
② 검사 요청 방법
③ 사용자 권한 검사
④ 속도 제한
⑤ 포맷 응답 데이터

use yii\filters\auth\CompositeAuth;
use yii\filters\ContentNegotiator;
use yii\filters\RateLimiter;
use yii\web\Response;
use yii\filters\VerbFilter;
/**
 * Controller is the base class for RESTful API controller classes.
 *
 * Controller implements the following steps in a RESTful API request handling cycle
 * 1. Resolving response format (see [[ContentNegotiator]]);
 * 2. Validating request method (see [[verbs()]]).
 * 3. Authenticating user (see [[\yii\filters\auth\AuthInterface]]);
 * 4. Rate limiting (see [[RateLimiter]]);
 * 5. Formatting response data (see [[serializeData()]])
behaviors
  contentNegotiator
  verbFilter
  authenticator
  rateLimiter
afterAction
  serializeData Yii::createObject($this->serializer)->serialize($data)
verbs []
*/
class Controller extends \yii\web\Controller
{
  public $serializer = 'yii\rest\Serializer';
  public $enableCsrfValidation = false;
  public function behaviors()
  {
    return [
      'contentNegotiator' => [
        'class' => ContentNegotiator::className(),
        'formats' => [
          'application/json' => Response::FORMAT_JSON,
          'application/xml' => Response::FORMAT_XML,
        ],
      ],
      'verbFilter' => [
        'class' => VerbFilter::className(),
        'actions' => $this->verbs(),
      ],
      'authenticator' => [
        'class' => CompositeAuth::className(),
      ],
      'rateLimiter' => [
        'class' => RateLimiter::className(),
      ],
    ]
  }
  public function verbs()
  {
    return [];
  }
  public function serializeData($data)
  {
    return Yii::createObject($this->serializer)->serialize($data);
  }
  public function afterAction($action, $result)
  {
    $result = parent::afterAction($action, $result);
    return $this->serializeData($result);
  }
}

2. rest/ActiveController ~ rest/Controller
Active Controller 는 일련의 Active Record 와 데 이 터 를 연결 하 는 RESTful 방법 을 실현 했다.
ActiveRecord 의 클래스 이름 은 model Class 변수 에 의 해 가리 키 며,yii\db\\ActiveRecord Interface??
기본적으로 다음 방법 을 지원 합 니 다:
 * - `index`: list of models
 * - `view`: return the details of a model
 * - `create`: create a new model
 * - `update`: update an existing model
 * - `delete`: delete an existing model
 * - `options`: return the allowed HTTP methods
actions()를 덮어 쓰 고 unsetting 이 응답 하 는 action 을 통 해 기본 동작 을 사용 하지 않 을 수 있 습 니 다.
새로운 동작 을 추가 하려 면 actions()를 덮어 쓰 고 끝 에 새로운 action class 나 새로운 action method 를 추가 하 십시오.
새로운 동작 이 HTTP Method 를 지원 하 는 지 확인 하기 위해 verbs()방법 을 덮어 쓰 는 지 주의 하 십시오.
현재 사용자 가 응답 하 는 동작 을 수행 할 수 있 는 권한 이 있 는 지 확인 하려 면 checkAccess()를 덮어 써 야 합 니 다.
위의 설명 에 따라 Controller 를 다시 한 번 쓰 겠 습 니 다.

class ActiveController extends Controller
{
  public #modelClass;
  public $updateScenario = Model::SCENARIO_DEFAULT;
  public $createScenario = Model::SCENARIO_DEFAULT;
  public function init()
  {
    parent::init();
    if($this->modelClass == null){
      throw new InvalidConfigException('The "modelClass" property must be set.');
    }
  }
  public function actions()
  {
    return [
      'index' => [
        'class' => 'app\controllers\rest\IndexAction',
        'modelClass' => $this->modelClass,
        'checkAccess' => [$this, 'checkAccess'],
      ],
      'view'...
      'create'...
      'update'...
      'delete'...
      'options'...
    ];
  }
  protected function verbs()
  {
    return [
      'index' => ['GET', 'HEAD'],
      'view' =>['GET', 'HEAD'],
      'create' =>['POST'],
      'update' =>['PUT', 'PATCH'],
      'delete' =>['DELETE'],
    ];
  }
  public function checkAccess($action, $model=null, $params = [])
  {
  }
}

다음은 이 rest\ActiveControler 를 계승 하 는 뉴스 컨트롤 러 를 실현 합 니 다.

namespace app\controllers;
use app\controllers\rest\ActiveController; #    AC,  yii/rest         
class NewsController extends ActiveController
{
  public $modelClass ='app\models\News';
}

여기까지 정의 하면 rest\Active Controller 의 기본 방법 을 실현 할 수 있 습 니 다.
다음은 덮어 쓰 고 맞 춤 형 방법 을 실현 합 니 다.

class NewsController extends ActiveController
{
  public $modelClass = 'app\models\News';
  #  serializer
  #public $serializer = 'yii\rest\Serializer';
  public $serializer = [
    'class' => 'app\controllers\rest\Serializer',
    'collectionEnvelope' => 'items',
  ];
  public function behaviors()
  {
    $be = ArrayHelper::merge(
      parent::behaviors(),
      [
        'verbFilter' => [
          'class' => VerbFilter::className(),
          'actions' => [
            'index' => ['get'],
            ...
          ]
        ],
        'authenticator' => [
          'class' => CompositeAuth::className(),
          'authMethods' => [
            HttpBasicAuth::className(),
            HttpBearerAuth::className(),
            QueryParamAuth::className(),
          ]
        ],
        'contentNegotiator' => [
          'class' => ContentNegotiator::className(),
          'formats' => [
            'text/html' => Response::FORMAT_HTML,
          ]
        ],
        'access' => [
          'class' => AccessControl::className(),
          'only' => ['view'],
          'rules' => [
            [
             'actions' => ['view'],
             'allow' => false,
             'roles' => ['@'],
            ],
         ],
        ]
      ],
    );
    return $be;
  }
  public function checkAccess()
  {
  }
}

3.맞 춤 형 동작
Actions 를 크게 변경 하려 면 원본 yii\rest\XXXAction 네 임 스페이스 를 사용 하지 말고 복사 하 는 것 을 권장 합 니 다.
저 는 여기 서 related models 에 대한 CURD 작업 을 목표 로 큰 변경 을 진행 하고 있 습 니 다.
Action
각 action 을 맞 추기 전에 기본 클래스 인 rest\Action 을 살 펴 보 세 요.주로 findModel 의 방법 입 니 다.

class Action extend \yii\base\Action
{
  public $modelClass;
  public $findModel;
  public $checkAccess;
  public function init()
  {
    if($this->modelClass == null) {
      throw new InvalidConfigException(get_class($this). '::$modelClass must be set');
    }
  }
  public function findModel($id)
  {
    if($this->findModel !== null) {
      return call_user_func($this->findModel, $id, $this);
    }
    $modelClass = $this->modelClass;
    $keys = $modelClass::primaryKey();
    if(count($keys) > 1) {
      $values = explode(',', $id);
      if..
    } elseif($id !== null) {
      $model = $modelClass::findOne($id);
    }
    if(isset($model)){
      return $model;
    }else {
      throw new NotFoundHttpException("Object not found: $id");
    }
  }
}

view
view 동작 은 변경 할 필요 가 없습니다.model 은 get 관련 자체 메커니즘 이 있 기 때 문 입 니 다.

class ViewAction extend Action
{
  public function run($id)
  {
    $model = $this->findModel($id);
    if($this->checkAccess) {
      call_user_func($this->checkAccess, $this->id, $model);
    }
  }
}

update

public function run($id)
{
  /* @var $model ActiveRecord */
  $model = $this->findModel($id);
  if ($this->checkAccess) {
   call_user_func($this->checkAccess, $this->id, $model);
  }
  $model->scenario = $this->scenario;
  $model->load(Yii::$app->getRequest()->getBodyParams(), '');
  $model->save();
  return $model;
}

개 조 를 거 친 후 관련 모델 에 대한 update 동작 을 만족 시 켜 야 합 니 다.

public function run($id)
{
  /* @var $model ActiveRecord */
  $model = $this->findModel($id);
  if ($this->checkAccess) {
   call_user_func($this->checkAccess, $this->id, $model);
  }
  $model->scenario = $this->scenario;
    /*
     *
     * x-www-form-urlencoded key=>value
     * image mmmmmmmm
     * link nnnnnnnnnn
     * newsItem[title]=>ttttttttttt , don't use newsItem["title"]
     * newsItem[body]=>bbbbbbbbbbb
     * don't use newsItem=>array("title":"tttttt","body":"bbbbbbb")
     * don't use newsItem=>{"title":"ttttttt","body":"bbbbbbbb"}
     *
     */
    $newsItem = Yii::$app->getRequest()->getBodyParams()['newsItem'];
    /*
      Array
      (
        [title] => ttttttttttt
        [body] => bbbbbbbbbbb
      )
     */
    $model->newsItem->load($newsItem, '');
    #$model->newsItem->load(Yii::$app->getRequest()->getBodyParams(), '');
    #print_R($model->newsItem);exit;
    #print_R($model->newsItem);exit;
    if($model->save())
    {
      $model->load(Yii::$app->getRequest()->getBodyParams(), '');
      $model->newsItem->save();
    }
  return $model;
}

뉴스 아 이 템 save 가 실 패 했 을 경우 처리 하지 않 아야 합 니 다.
Yii 관련 내용 에 관심 이 있 는 독자 들 은 본 사이트 의 주 제 를 볼 수 있다.
본 고 는 Yii 프레임 워 크 를 기반 으로 한 PHP 프로 그래 밍 에 도움 이 되 기 를 바 랍 니 다.

좋은 웹페이지 즐겨찾기