Installing the Project

I’ve chosen the Yii advanced version here. If you don’t have a running environment, you can refer to the official documentation to install the running environment using Vagrant.

Since I already have a PHP runtime environment locally, I’ll use Composer to create the project directly:

composer create-project --prefer-dist yiisoft/yii2-app-advanced service

Enter the project directory and initialize the project:

$ cd service
$ php init
Yii Application Initialization Tool v1.0

Which environment do you want the application to be initialized in?

  [0] Development
  [1] Production

  Your choice [0-1, or "q" to quit] 0

  Initialize the application under 'Development' environment? [yes|no] yes

  Start initialization ...

   generate frontend/config/test-local.php
   generate frontend/config/params-local.php
   generate frontend/config/main-local.php
   generate frontend/config/codeception-local.php
   generate frontend/web/index.php
   generate frontend/web/robots.txt
   generate frontend/web/index-test.php
   generate yii
   generate backend/config/test-local.php
   generate backend/config/params-local.php
   generate backend/config/main-local.php
   generate backend/config/codeception-local.php
   generate backend/web/index.php
   generate backend/web/robots.txt
   generate backend/web/index-test.php
   generate common/config/test-local.php
   generate common/config/params-local.php
   generate common/config/main-local.php
   generate common/config/codeception-local.php
   generate yii_test.bat
   generate yii_test
   generate console/config/test-local.php
   generate console/config/params-local.php
   generate console/config/main-local.php
   generate cookie validation key in backend/config/main-local.php
   generate cookie validation key in common/config/codeception-local.php
   generate cookie validation key in frontend/config/main-local.php
      chmod 0777 backend/runtime
      chmod 0777 backend/web/assets
      chmod 0777 console/runtime
      chmod 0777 frontend/runtime
      chmod 0777 frontend/web/assets
      chmod 0755 yii
      chmod 0755 yii_test

  ... initialization completed.

After installation, the directory structure is as follows:

$ tree -L 1
.
├── LICENSE.md
├── README.md
├── Vagrantfile
├── backend
├── codeception.yml
├── common
├── composer.json
├── composer.lock
├── console
├── docker-compose.yml
├── environments
├── frontend
├── init
├── init.bat
├── requirements.php
├── vagrant
├── vendor
├── yii
├── yii.bat
├── yii_test
└── yii_test.bat

7 directories, 14 files

Next, we will modify the routing functionality in the backend app.

Module

Generation

Use gii to generate a Module for the project. As you can see below, I generated an auth Module:

$ php yii gii/module --moduleClass='backend\modules\auth\Module' --moduleID=auth
Running 'Module Generator'...

The following files will be generated:
        [new] /Users/George/Develop/PHP/service/backend/modules/auth/Module.php
        [new] /Users/George/Develop/PHP/service/backend/modules/auth/controllers/DefaultController.php
        [new] /Users/George/Develop/PHP/service/backend/modules/auth/views/default/index.php

Ready to generate the selected files? (yes|no) [yes]:yes

Files were generated successfully!
Generating code using template "/Users/George/Develop/PHP/service/vendor/yiisoft/yii2-gii/src/generators/module/default"...
 generated /Users/George/Develop/PHP/service/backend/modules/auth/Module.php
 generated /Users/George/Develop/PHP/service/backend/modules/auth/controllers/DefaultController.php
 generated /Users/George/Develop/PHP/service/backend/modules/auth/views/default/index.php
done!

Registration

Edit the backend\config\main.php file and add the auth Module to modules:

'modules' => [
    'auth' => ['class' => 'backend\modules\auth\Module'],
],

And modify the urlManager property as follows:

'urlManager' => [
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'enableStrictParsing' => false,
    'rules' => [
        '<modules>/<controller>' => '<modules>/<controller>/enter'
    ],
],

The main part is the rules section, which routes all requests to the enter method of the corresponding Controller in the corresponding Module. The purpose of doing this is to be able to handle all requests uniformly.

Controller for Handling Unified Logic

Create Controller

Create the common\controllers\RestController.php controller with the following content:

<?php

namespace common\controllers;

use Yii;
use yii\base\Action;
use ReflectionException;
use yii\rest\Controller;
use yii\base\InlineAction;
use yii\base\InvalidRouteException;
use yii\base\InvalidConfigException;

/**
 * Date: 2019/1/1
 * @author George <[email protected]>
 * @package common\controllers
 */
class BaseController extends Controller
{
    /**
     * Unified request handling
     * 
     * Date: 2019/1/1
     * @return mixed
     * @throws InvalidRouteException
     * @author George
     */
    public function main()
    {
        $request = Yii::$app->request;
        $method = strtolower($request->getMethod());
        $params = array_merge($request->get(), $request->post());
        // Your unified business logic to handle
        $result = $this->runAction($method, ['params' => $params]);
        return $result;
    }

    /**
     * Date: 2019/1/1
     * @param array $params
     * @return array
     * @author George <[email protected]>
     */
    public function post(array $params = []): array
    {
        return [];
    }

    /**
     * Date: 2019/1/1
     * @param array $params
     * @return array
     * @author George <[email protected]>
     */
    public function put(array $params = []): array
    {
        return [];
    }

    /**
     * Date: 2019/1/1
     * @param array $params
     * @return array
     * @author George <[email protected]>
     */
    public function get(array $params = []): array
    {
        return [];
    }

    /**
     * Using method name index instead of actionIndex
     *
     * Date: 2019/1/1
     * @param string $id
     * @return object|Action|InlineAction|null
     * @throws ReflectionException
     * @throws InvalidConfigException
     * @author George <[email protected]>
     */
    public function createAction($id)
    {
        if ($id === '') {
            $id = $this->defaultAction;
        }

        $actionMap = $this->actions();
        if (isset($actionMap[$id])) {
            return Yii::createObject($actionMap[$id], [$id, $this]);
        }

        if (preg_match('/^(?:[a-z0-9_]+-)*[a-z0-9_]+$/', $id)) {
            $methodName = $id;
            if (method_exists($this, $methodName)) {
                $method = new \ReflectionMethod($this, $methodName);
                if ($method->isPublic() && $method->getName() === $methodName) {
                    return new InlineAction($id, $this, $methodName);
                }
            }
        }

        return null;
    }
}

Inherit Controller

Have all Module Controllers in the project inherit from the common\controllers\RestController created above.

<?php

namespace backend\modules\auth\controllers;

use common\controllers\RestController;

/**
 * User SingIn Controller logic
 * 
 * Date: 2019/1/1
 * @author George <[email protected]>
 * @package backend\modules\auth\controllers
 */
class SigninController extends RestController
{
    public function post(array $params = []): array
    {
        return $params;
    }
}

At this point, it’s basically complete. Now when you request POST /auth/signin, it will automatically route to the post method of the SigninController.

I hope this is helpful, Happy hacking…