# 快速入门

## 需求

假如我们要开发一个商品模块，我们将它命名为 ItemBundle ，其包含了商品、sku、商品类型、标签，可以实现商品相关的增删改查。

## 环境说明

本文档是用的开发环境是官方的 docker 环境，[点此查看](https://github.com/shopex/ecshopx-dev-docker)，其他环境使用命令时请按需修改。

本文档所使用的 php artisan 命令，都需要进入容器内执行，进入容器的命令为：

```
docker exec -it ecshopx-dev-docker_espier-bloated-web_1 sh
```

## 开发说明

在使用 Doctrine Orm 开发应用程序时，可以使用以下三种方式来启动开发：

* Code First：首先要开发 Entity 类，然后将他们映射到数据库中
* Model First：需要是用工具对（UML）进行建模，并从改模型生成数据库和 Entity 类
* Database First：首先要设计数据表，然后根据数据表生成 Entity 类

### Code First

此方式需要根据需求设计 Entity 类，设计时需要熟知 Doctrine Orm 注解，只要熟悉数据库设计即可，所以用这种方式效率更高。此方式具体开发流程如下：

* 一、设计 Entity 类
* 二、通过命令生成数据库迁移

  ```
  php artisan doctrine:migrations:diff
  ```
* 三、生成数据表

  ```
  php artisan doctrine:migrations:migrate
  ```

> Ecstore 和 Bbc 和此方式类似

### Database First

此方式和 Database First 正好相反，先设计数据表，再生成 Entity 类。由于此方式不需要熟知 Doctrine Orm 注解，只要熟悉数据库设计即可，所以用这种方式效率更高。此方式具体开发流程如下：

* 一、采用数据库设计软件设计数据库 ER 图。
* 二、通过 ER 图生成的 SQL 创建数据表
* 三、通过命令生成实体

  ```
  php artisan doctrine:mapping:import annotation --filter=DemoUser --namespace=ItemBundle\\Entities\\
  ```

> \--filter=DemoUser 中的 DemoUser 是想要生成的实体名，是数据表的大驼峰写法，不写 --filter 将会把数据库中所有的数据表都生成 Entity 放到 src/ItemBundle/Entities 目录中

本教程将采用 `Database First` 的方式。

## 设计数据库

根据需求，我们通过 `Mysql Workbench` 来设计 ER 图：

![](/files/-LySR61DU8kMKM7bJX7I)

设计完 ER 图之后，在 `Mysql Workbench` 中可以通过 `Database-> Forward Engineer` 直接将 ER 图直接生成数据表。 为了方便讲解，我们将此 ER 图生成的 SQL 放在此处，方便大家直接创建数据库：

```sql
-- -----------------------------------------------------
-- Table `mydb`.`item_type`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`item_type` ;

CREATE TABLE IF NOT EXISTS `mydb`.`item_type` (
  `id` BIGINT NOT NULL,
  `name` VARCHAR(255) NOT NULL COMMENT '名称',
  `code` VARCHAR(64) NOT NULL COMMENT '编码',
  `updated` INT(11) NOT NULL,
  `created` INT(11) NULL,
  PRIMARY KEY (`id`))
COMMENT = '类型表';


-- -----------------------------------------------------
-- Table `mydb`.`item`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`item` ;

CREATE TABLE IF NOT EXISTS `mydb`.`item` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `item_type_id` BIGINT NOT NULL COMMENT '类型',
  `name` VARCHAR(255) NOT NULL COMMENT '名称',
  `price` DECIMAL(20,3) NOT NULL COMMENT '价格',
  `created` INT(11) UNSIGNED NOT NULL COMMENT '创建时间',
  `updated` INT(11) NULL COMMENT '最后更新时间',
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_item_item_type`
    FOREIGN KEY (`item_type_id`)
    REFERENCES `mydb`.`item_type` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
COMMENT = '商品';

CREATE INDEX `fk_item_item_type_idx` ON `mydb`.`item` (`item_type_id` ASC);


-- -----------------------------------------------------
-- Table `mydb`.`sku`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`sku` ;

CREATE TABLE IF NOT EXISTS `mydb`.`sku` (
  `id` BIGINT NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(255) NOT NULL COMMENT '名称',
  `price` DECIMAL(20,3) NOT NULL COMMENT '价格',
  `created` INT(11) NOT NULL,
  `updated` INT(11) NULL,
  `store` VARCHAR(45) NULL COMMENT '库存',
  `spec1` VARCHAR(45) NULL COMMENT '规格 1',
  `spec2` VARCHAR(45) NULL COMMENT '规格 2\n',
  `item_id` BIGINT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_sku_item1`
    FOREIGN KEY (`item_id`)
    REFERENCES `mydb`.`item` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
COMMENT = 'SKU';

CREATE INDEX `fk_sku_item1_idx` ON `mydb`.`sku` (`item_id` ASC);


-- -----------------------------------------------------
-- Table `mydb`.`tag`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`tag` ;

CREATE TABLE IF NOT EXISTS `mydb`.`tag` (
  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(60) NOT NULL COMMENT '标签名称',
  `updated` INT(11) NOT NULL,
  `created` INT(11) NULL,
  PRIMARY KEY (`id`))
COMMENT = '标签';


-- -----------------------------------------------------
-- Table `mydb`.`item_tag`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`item_tag` ;

CREATE TABLE IF NOT EXISTS `mydb`.`item_tag` (
  `item_id` BIGINT NOT NULL,
  `tag_id` BIGINT UNSIGNED NOT NULL,
  PRIMARY KEY (`item_id`, `tag_id`),
  CONSTRAINT `fk_item_tag_item1`
    FOREIGN KEY (`item_id`)
    REFERENCES `mydb`.`item` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_item_tag_tag1`
    FOREIGN KEY (`tag_id`)
    REFERENCES `mydb`.`tag` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

CREATE INDEX `fk_item_tag_tag1_idx` ON `mydb`.`item_tag` (`tag_id` ASC);

CREATE INDEX `fk_item_tag_item1_idx` ON `mydb`.`item_tag` (`item_id` ASC);
```

## 生成实体类

我们可以通过命令行生成 Entity 类

```
php artisan doctrine:mapping:import annotation --namespace=ItemBundle\\Entities\\
```

生成 Entity 成功后可以看到以下输出：

```
Importing mapping information from "mydb" entity manager
  > writing /app/src/ItemBundle/Entities/Item.php
  > writing /app/src/ItemBundle/Entities/ItemType.php
  > writing /app/src/ItemBundle/Entities/Sku.php
  > writing /app/src/ItemBundle/Entities/Tag.php
```

以 ItemType 实体为例，打开 ItemType.php 可以看到以下内容：

```php
<?php

namespace ItemBundle\Entities;

use Doctrine\ORM\Mapping as ORM;

/**
 * ItemType
 *
 * @ORM\Table(name="item_type")
 * @ORM\Entity
 */
class ItemType
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="bigint", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255, nullable=false, options={"comment"="名称"})
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="code", type="string", length=64, nullable=false, options={"comment"="编码"})
     */
    private $code;

    /**
     * @var int
     *
     * @ORM\Column(name="updated", type="integer", nullable=false)
     */
    private $updated;

    /**
     * @var int|null
     *
     * @ORM\Column(name="created", type="integer", nullable=true)
     */
    private $created;


}
```

生成实体类的 Getter 和 Setter

根据数据表生成的实体类，只有 `private` 的属性，我们还需要为其设置 Getter 和 Setter 方法，可以以下命令生成：

```
php artisan doctrine:generate:entities --filter=ItemType
```

## 定义接口

一个接口对一个一条路由，一个路由对应一个控制器方法。

### 定义控制器

我们先来完成 ItemType 实体的增删改查操作。

先创建一个带有增删改查空方法的控制器：

```php
<?php
//src/ItemBundle/Http/Api/V1/Action/ItemTypesController.php
namespace ItemBundle\Http\Api\V1\Action;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller as BaseController;
use Dingo\Api\Exception\StoreResourceFailedException;

class ItemTypesController extends BaseController
{
    public function  index(Request $request) {
        return $this->response->array([]);
    }
    public function save(Request $request) {
        return $this->response->array([]);
    }

    public function  show(Request $request, $id) {
        return $this->response->array([$id]);
    }
    public function  update(Request $request, $id) {

    }
    public function  destroy(Request $request, $id) {

    }

}
```

### 定义路由

```php
<?php
//routes/api/item.php
$api->version('v1', function($api) {
    $api->group(['namespace' => 'ItemBundle\Http\Api\V1\Action','middleware' => [], 'providers' => 'jwt'], function($api) {
        $api->get('/item_types', ['name' => '获取商品类型列表', 'as' => 'item_types. list', 'uses'=>'ItemTypesController@index']);
        $api->post('/item_types', ['name' => '创建商品类型', 'as' => 'item_types.save', 'uses'=>'ItemTypesController@save']);
        $api->get('/item_types/{id}', ['name' => '获取商品类型详情', 'as' => 'item_types.show', 'uses'=>'ItemTypesController@show']);
        $api->put('/item_types/{id}/', ['name' => '更新商品类型', 'as' => 'item_types.update', 'uses'=>'ItemTypesController@update']);
        $api->delete('/item_types', ['name' => '删除商品类型', 'as' => 'item_types.destroy', 'uses'=>'ItemTypesController@destroy']);
    });
});
```

此时，可以通过浏览器访问 <http://127.0.0.1:8080/api/item_types> 获取商品类型列表接口。

### 定义接口文档

#### 一、定义 ItemBundle 接口文档分组

基本信息：

```php
<?php
//src/ItemBundle/Http/Api/V1/Swagger/Info.php
/**
 * @SWG\Swagger(
 *    swagger="2.0",
 *    schemes={"http"},
 *    host="localhost",
 *    basePath="/espier/public/index.php/api/",
 *    @SWG\Info(
 *        version="1.0",
 *        title="商品相关接口",
 *        description="item api",
 *    ),
 * )
*/
```

接口标签

```php
<?php
//src/ItemBundle/Http/Api/V1/Swagger/Tags.php
/**
 * @SWG\Tag(
 *   name="ItemCrud",
 *   description="商品增删改查相关",
 * )
 */

/**
 * @SWG\Tag(
 *   name="ItemTag",
 *   description="商品标签",
 * )
 */
```

接口统一错误响应结构体：

```php
<?php
//src/ItemBundle/Http/Api/V1/Swagger/ItemsErrorRespones.php
namespace src\GoodsBundle\Http\Api\V1\Swagger;
/**
 * @SWG\Definition(type="object")
 */
class ItemsErrorRespones
{
    /**
     * @SWG\Property
     * @var string
     */
    public $message;

    /**
     * @SWG\Property
     * @var string
     */
    public $errors;

    /**
     * @SWG\Property(format="int32")
     * @var int
     */
    public $code;

    /**
     * @SWG\Property(format="int32")
     * @var int
     */
    public $status_code;

    /**
     * @SWG\Property
     * @var string
     */
    public $debug;
}
```

#### 二、定义具体接口的输入和输出

```php
<?php
//src/ItemBundle/Http/Api/V1/Action/ItemTypesController.php
namespace ItemBundle\Http\Api\V1\Action;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller as BaseController;
use Dingo\Api\Exception\StoreResourceFailedException;

class ItemTypesController extends BaseController
{

    /**
     * @SWG\Get(
     *     path="/item_types",
     *     summary="获取商品类型列表",
     *     tags={"ItemType"},
     *     description="获取商品类型列表",
     *     operationId="index",
     *     @SWG\Response(
     *         response=200,
     *         description="成功返回结构",
     *         @SWG\Schema(
     *             @SWG\Property(
     *                 property="data",
     *                 type="array",
     *                 @SWG\Items(
     *                     type="object",
     *                     @SWG\Property(property="status", type="stirng"),
     *                 )
     *             ),
     *          ),
     *     ),
     *     @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/ItemsErrorRespones") ) )
     * )
     */
    public function  index(Request $request) {
        return $this->response->array([]);
    }
    /**
     * @SWG\Post(
     *     path="/item_types",
     *     summary="新增商品类型",
     *     tags={"ItemType"},
     *     description="新增商品类型",
     *     operationId="save",
     *     @SWG\Parameter( name="name", in="formData", description="类型名称", required=true, type="string"),
     *     @SWG\Parameter( name="code", in="formData", description="类型描述", required=true, type="string"),
     *     @SWG\Response(
     *         response=200,
     *         description="成功返回结构",
     *         @SWG\Schema(
     *             @SWG\Property(
     *                 property="data",
     *                 type="array",
     *                 @SWG\Items(
     *                     type="object",
     *                     @SWG\Property(property="id", type="integer"),
     *                     @SWG\Property(property="name", type="string"),
     *                     @SWG\Property(property="code", type="string"),
     *                )
     *             ),
     *          ),
     *     ),
     *     @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/ItemsErrorRespones") ) )
     * )
     */
    public function save(Request $request) {
        return $this->response->array([]);
    }
    /**
     * @SWG\Get(
     *     path="/item_types/{id}",
     *     summary="获取商品详情",
     *     tags={"ItemType"},
     *     description="获取商品类型列表",
     *     operationId="show",
     *     @SWG\Parameter( name="id", in="path", description="类型名称", required=true, type="string"),
     *     @SWG\Response(
     *         response=200,
     *         description="成功返回结构",
     *         @SWG\Schema(
     *             @SWG\Property(
     *                 property="data",
     *                 type="array",
     *                 @SWG\Items(
     *                     type="object",
     *                     @SWG\Property(property="status", type="stirng"),
     *                 )
     *             ),
     *          ),
     *     ),
     *     @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/ItemsErrorRespones") ) )
     * )
     */
    public function  show(Request $request,$id) {
        return $this->response->array([$id]);
    }
    /**
     * @SWG\Put(
     *     path="/item_types/{id}",
     *     summary="更新商品类型",
     *     tags={"ItemType"},
     *     description="获取商品类型列表",
     *     operationId="update",
     *     @SWG\Parameter( name="id", in="path", description="类型名称", required=true, type="string"),
     *     @SWG\Parameter( name="name", in="formData", description="类型名称", required=false, type="string"),
     *     @SWG\Parameter( name="code", in="formData", description="类型描述", required=false, type="string"),
     *     @SWG\Response(
     *         response=200,
     *         description="成功返回结构",
     *         @SWG\Schema(
     *             @SWG\Property(
     *                 property="data",
     *                 type="array",
     *                 @SWG\Items(
     *                     type="object",
     *                     @SWG\Property(property="status", type="stirng"),
     *                 )
     *             ),
     *          ),
     *     ),
     *     @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/ItemsErrorRespones") ) )
     * )
     */
    public function  update(Request $request, $id) {

    }
    /**
     * @SWG\Delete(
     *     path="/item_types/{id}",
     *     summary="删除商品类型",
     *     tags={"ItemType"},
     *     description="删除商品类型",
     *     operationId="destroy",
     *     @SWG\Parameter( name="id", in="path", description="类型名称", required=true, type="string"),
     *     @SWG\Response(
     *         response=200,
     *         description="成功返回结构",
     *         @SWG\Schema(
     *             @SWG\Property(
     *                 property="data",
     *                 type="array",
     *                 @SWG\Items(
     *                     type="object",
     *                     @SWG\Property(property="status", type="stirng"),
     *                 )
     *             ),
     *          ),
     *     ),
     *     @SWG\Response( response="default", description="错误返回结构", @SWG\Schema( type="array", @SWG\Items(ref="#/definitions/ItemsErrorRespones") ) )
     * )
     */
    public function  destroy(Request $request, $id) {

    }

}
```

#### 三、接口文档

接口文档的生成请参阅 \[[接口文档生成和接口测试](https://espier.gitbook.io/espier/pages/-Lx5R6Sk-eoJVuCFv8A-#接口文档生成和接口测试)]

```
php artisan api:swagger --output=src/ItemBundle/Http/Api/V1 && php -S 0.0.0.0:8005 -t public/
```

成功之后，将会看到以下界面：

![](/files/-LySR61LfLl3FGjDpEI0)

## 实现商品类型的 CRUD

我们以 MVC 架构为基础，加入 [Repository 模式](broken://pages/-LwXhK_kdobhdfy_vNal) 和 [Service 模式](broken://pages/-LwXhK_lVJAYFePc2zye)来完成我们的开发。

### 第一步：新增相关类

新建与 ItemType 相关的 Service 和 Repository 类。

新建 ItemTypeSecvice 类：

```php
//src/ItemBundle/Services/ItemTypeSercice.php
<?php
namespace ItemBundle\Services;

class ItemTypeService
{

}
```

新建 ItemTypeRepository 类：

```php
//src/ItemBundle/Repositories/ItemTypeRepository.php
<?php
namespace ItemBundle\Repositories;
use Doctrine\ORM\EntityRepository;

class ItemTypeRepository extends EntityRepository
{

}
```

同时修改 ItemType 类与之相关联：

```php
<?php
//src/ItemBundle/Entities/ItemType.php
namespace ItemBundle\Entities;

use Doctrine\ORM\Mapping as ORM;
/**
 * ItemType
 *
 * @ORM\Table(name="item_type")
 * @ORM\Entity(repositoryClass="ItemBundle\Repositories\ItemTypeRepository")
 */
class ItemType
{
    //...
}
```

### 第二步：确定调用关系

采用 Service 和 Repository 模式，相关类的调用关系为 Controller->Service->Repository 。

我们利用 Laravel 自带的依赖注入的方式，在 Controller 中新增构造方法来初始化 Service 类

```php
<?php
//src/ItemBundle/Http/Api/V1/Action/ItemTypesController.php
namespace ItemBundle\Http\Api\V1\Action;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller as BaseController;
use Dingo\Api\Exception\StoreResourceFailedException;
use ItemBundle\Entities\ItemType;
use Dingo\Api\Exception\ResourceException;
use ItemBundle\Services\ItemTypeService;

class ItemTypesController extends BaseController
{
    protected $itemTypeService;

    public function __construct(ItemTypeService $itemTypeService)
    {
        $this->itemTypeService = $itemTypeService;
    }

    //...

}
```

因为初始化 Repository 类需要特定的方法，所以在 ItemTypeSecvice 类中，我们需要手动初始化 Repository 类：

```php
//src/ItemBundle/Services/ItemTypeSercice.php
<?php
namespace ItemBundle\Services;

use ItemBundle\Entities\ItemType;

class ItemTypeService
{
    protected $itemTypeRepository;

    public function __construct()
    {
        $this->itemTypeRepository = app('registry')->getManager('default')->getRepository(ItemType::class);
    }
}
```

### 第三步：编写逻辑

ItemTypeRepository 类

```php
//src/ItemBundle/Repositories/ItemTypeRepository.php
<?php
namespace ItemBundle\Repositories;

use ItemBundle\Entities\ItemType;
use Doctrine\ORM\EntityRepository;

class ItemTypeRepository extends EntityRepository
{

    public function store(ItemType $itemType)
    {
        $em = $this->getEntityManager();
        $em->persist($itemType);
        $em->flush();
        return $itemType;
    }
    public function delete(ItemType $itemType)
    {
        $em = $this->getEntityManager();
        $em->remove($itemType);
        $em->flush();
        return $itemType;
    }
}
```

ItemTypeSercice 类：

```php
//src/ItemBundle/Services/ItemTypeSercice.php
<?php
namespace ItemBundle\Services;

use ItemBundle\Entities\ItemType;

class ItemTypeService
{
    protected $itemTypeRepository;

    public function __construct()
    {
        $this->itemTypeRepository = app('registry')->getManager('default')->getRepository(ItemType::class);
    }

    public function create($params)
    {
        $itemType = new ItemType();
        $itemType->setName($params['name']);
        $itemType->setCode($params['code']);
        $itemType->setCreated(time());

        return $this->itemTypeRepository->store($itemType);
    }

    public function update($id,$data)
    {
        $itemType = $this->itemTypeRepository->find($id);

        if( !$itemType ) {
            throw new ResourceException("未查询到更新数据");
        }
        $itemType->setName($data['name']);
        $itemType->setCode($data['code']);
        $itemType->setUpdated(time());
        return $this->itemTypeRepository->store($itemType);
    }
    public function deleteById($id)
    {
        $itemType = $this->itemTypeRepository->find($id);

        if( !$itemType ) {
            throw new ResourceException("未查询到更新数据");
        }
        return $this->itemTypeRepository->delete($itemType);
    }
    public function findAll()
    {
        return $this->itemTypeRepository->findAll();
    }
    public function find($id)
    {
        return $this->itemTypeRepository->find($id);
    }
    public function toArray(ItemType $itemType)
    {
        return [
            'id'=>$itemType->getId(),
            'name'=>$itemType->getName(),
            'code'=>$itemType->getCode(),
            'created'=>$itemType->getCreated(),
            'updated'=>$itemType->getUpdated(),
        ];
    }
}
```

控制器

```php
<?php
//src/ItemBundle/Http/Api/V1/Action/ItemTypesController.php
namespace ItemBundle\Http\Api\V1\Action;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller as BaseController;
use Dingo\Api\Exception\StoreResourceFailedException;
use ItemBundle\Entities\ItemType;
use Dingo\Api\Exception\ResourceException;
use ItemBundle\Services\ItemTypeService;

class ItemTypesController extends BaseController
{

    protected $itemTypeService;

    public function __construct(ItemTypeService $itemTypeService)
    {
        $this->itemTypeService = $itemTypeService;
    }
    public function  index(Request $request) {
        $list = $this->itemTypeService->findAll();
        foreach ($list as $itemType) {
            $result[] = $this->itemTypeService->toArray($itemType); 
        }
        return $this->response->array($result);
    }
    public function save(Request $request) {
        $rules = [
            'name'    => ['required', '类型名称不能为空'],
            'code'   => ['required', '类型编码不能为空'],
        ];
        $params = $request->all(array_keys($rules));
        $error = validator_params($params, $rules);

        if($error) {
            throw new StoreResourceFailedException($error);
        } 

        $itemType = $this->itemTypeService->create($params);

        return $this->response->array(['id'=>$itemType->getId()]);
    }

    public function show(Request $request,$id) {
        $itemType = $this->itemTypeService->find($id);
        return $this->response->array($this->itemTypeService->toArray($itemType));
    }

    public function  update(Request $request, $id) {
        $rules = [
            'name'    => ['required', '类型名称不能为空'],
            'code'   => ['required', '类型编码不能为空'],
        ];
        $params = $request->all(array_keys($rules));
        $error = validator_params($params, $rules);

        if($error) {
            throw new StoreResourceFailedException($error);
        }

        $itemType = $this->itemTypeService->update($id,$params);

        return $this->response->array(['status'=>'succ']);
    }

    public function  destroy(Request $request, $id) {
        $itemType = $this->itemTypeService->deleteById($id);
        return $this->response->array(['status'=>'succ']);
    }

}
```

## 未完待续


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://espier.gitbook.io/espier/start.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
