forensic/handler

位于控制器和模型之间,执行请求数据验证、序列化和完整性检查

v1.0.1 2018-10-22 14:22 UTC

This package is auto-updated.

Last update: 2024-09-23 08:02:33 UTC


README

Build Status Coverage Status semantic-release Packagist

Forensic Handler 是一个位于控制器和模型之间的独立 PHP 模块,执行请求数据验证、序列化和完整性检查。它易于设置,并且独立于任何 PHP 框架和 ORM。

它简化了验证过程,只需要定义数据验证规则,这些规则只是 PHP 数组。

最有趣的部分是验证字段数据和文件数组有多容易,以及它提供的广泛验证规则类型。它也可以扩展,以便在需要时定义更多验证规则。有关说明,请参阅 如何编写自定义验证类型

关于数据库完整性检查,它足够灵活,允许你通过定义一个抽象的 DBCheckerAbstract 类来将数据库检查的实现留给你。这使得它与任何框架或 ORM 无关。有关说明,请参阅 如何实现 DBCheckerAbstract 接口

入门

通过 composer 安装:

composer require forensic/handler

简单用法示例

处理器:

/**
 * file AuthHandler.php
*/
//make sure composer autoloader is loaded

namespace app\Handler;

use Forensic\Handler\Handler as BaseHandler;
use app\Model\UserModel; //our model

class AuthHandler extends BaseHandler
{
    public function getDB()
    {
        //return db orm
    }

    /**
     * executes signup
     *@param array|string [$source = 'post'] - the source of the data. can also be an array
    */
    public function executeSignup($source = 'post')
    {
        $rules = [
            //email field rule.
            'email' => [
                'type' => 'email',
                'err' => '{this} is not a valid email address'
            ],
            'password1' => [
                'type' => 'password',
            ],
            'password2' => [
                'type' => 'password',
                'matchWith' => '{password1}'
            ],
        ];

        $this->setSource($source)->setRules($rules);

        if (!$this->execute())
            return $this->succeeds(); //return immediately if there are errors

        /*
        * check if user exists, so that we dont create same user again
        * we can check using the model, or execute a prepared separate query. we could also
        * define this integrity check right in the rules above, only that we must implement
        * the DBCheckerAbstract class which will be shown later
        */
        $query = 'SELECT id FROM users WHERE email = ? AND password = ?';
        $result = $this->getDB()->select($query, array($this->email, $this->password1));
        if (count($result) > 0)
        {
            $this->setError('email', 'User already exists, please login instead');
            return $this->succeeds(); //return immediately if there is error
        }

        //create user
        $user = new UserModel();

        /**
         * do not copy password2 and rename password1 to just password when mapping processed
         * data to our model
        */
        $this->modelSkipField('password2')->modelRenameField('password1', 'password');
        $this->mapDataToModel($user)->save(); // it returns the model

        //set the new user id so that it can be accessed outside the class
        $this->setData('id', $user->id);

        return $this->succeeds();
    }
}

控制器:

/**
 * file auth controller
*/
namespace app\Controller;

use SomeNamespace\Request;
use SomeNamespace\JsonResponse;

use SomeNamespace\Controller as BaseController;
use app\Handler\AuthHandler;

class AuthController extends BaseController
{
    public function signup(Request $request, Response $response, AuthHandler $handler)
    {
        if ($handler->executeSignup())
            return $response([
                'status' => 'success',
                'data' => [
                    'userId' => $handler->id
                ],
            ]);
        else
            return $response([
                'status' => 'failed',
                'data' => [
                    'errors' => $handler->getErrors()
                ],
            ]);
    }
}

请注意,由于 PHP 的魔法 __get() 方法,可以直接在实例上访问处理后的数据。然而,如果您尝试访问未定义键的数据,则会抛出 KeyNotFoundException,以帮助进行故障排除。.

验证规则格式

验证规则定义为以字段名称为键的数组。每个字段数组可以包含以下规则属性

  1. type:这表示要对字段执行的验证类型。

  2. required:表示字段是否为必需的布尔值。默认为 true。

  3. default:此属性适用于非必需字段。默认值为 null。

  4. filters:定义应用于字段值之前的过滤器数组。

  5. check:包含要运行在字段值上的数据库完整性检查的数组。

  6. checks:包含要在字段值上运行的多项数据库完整性检查的数组。

  7. options:包含其他验证规则的数组。

  8. requiredIf:一个条件语句,如果满足条件,则使字段成为必需。

要引用验证原则,使用的约定是在字符串中将原则字段名称用大括号括起来。'{field-name}'。模块将找到并解决此类,用字段值替换它。

其他约定包括 {this},它引用正在验证的当前字段值;{_this} 引用正在验证的当前字段名;而 {_index} 引用正在验证的当前字段值索引位置(在验证字段数组的情况下)。

最后,还有 {CURRENT_DATE}{CURRENT_YEAR}{CURRENT_TIME},分别引用当前日期、当前年和当前时间戳值。

$rules = [
    'first-name' => [
        'type' => 'text',
        'options' => [
            'min' => 3,
            'minErr' => '{_this} should be at least 3 charaters length',
            //first-name should be at least 3 characters length
        ],
    ],
    //we are expecting an array of favorite colors
    'favorite-colors' => [
        'type' => 'choice',
        'filters' => [
            'toLower' => true, //convert the colors to lowercase
        ],
        'options' => [
            //choices to choose from
            'choices' => array('green', 'white', 'blue', 'red', 'violet', 'purple'),
            'err' => 'color {_index} is not a valid color',
            //color 1 is not a valid color'
        ],
    ],
    'subscribe-newsletter' => [
        'type' => 'boolean',
    ],
    //email is required if user checks the subscribe checkbox, else, do not require it
    'email' => [
        'type' => 'email',
        'requireIf' => [
            'condition' => 'checked',
            'field' => 'subscribe-newsletter'
        ]
        'err' => '{this} is not a valid email address'
    ],
]

验证过滤器

在验证之前应用于字段值。您可以使用过滤器在验证之前修改字段值。可用的过滤器包括

  1. decode:在字段值上调用 PHP 的 urldecode() 函数。默认为 true

  2. trim:在字段值上调用 PHP 的 trim() 函数。默认为 true

  3. stripTags:在字段值上调用 PHP 的 strip_tags() 函数。默认为 true

  4. stripTagsIgnore:定义当stripTags过滤器设置为true时不应删除的HTML标签字符串。默认为空字符串

  5. numeric:在字段值上调用php floatval()函数。默认为false

  6. toUpper:在字段值上调用php strtoupper()函数。默认为false

  7. toLower:在字段值上调用php strtolower()函数。默认为false

$rules = [
    'country' => [
        'filters' => [
            'toLower' => true //convert to lowercase
        ],
    ],
    'comment' => [
        'filter' => [
            'stripTagsIgnore' => '<p><br>'
        ],
    ],
];

验证规则类型

该模块定义了许多验证规则类型,覆盖了广泛的验证场景。以下是一些类型:

限制规则验证

限制规则验证选项影响每个验证。在这里,我们可以定义字符串、日期或数值值的最大长度。这些选项包括min(最小值)、max(最大值)、gt(大于)和lt(小于)。

$rules = [
    'first-name' => [
        'type' => 'text',
        'options' => [
            'min' => 3,
            'minErr' => 'first name should be at least 3 characters length',
            'max' => 15,
        ]
    ],
    'favorite-integer' => [
        'type' => 'positiveInteger',
        'options' => [
            'lt' => 101, //should be less than 101, or max of 100.
        ]
    ],
    'date-of-birth' => [
        'type' => 'date',
        'options' => [
            'min' => '01-01-1990', //only interested in people born on or after 01-01-1990
            'max' => '{CURRENT_DATE}'
        ]
    ],
];

正则表达式规则验证

对字段值执行不同类型的正则表达式规则测试非常简单。有四种正则表达式规则。包括单个regex测试、regexAnyregexAllregexNone测试。

regex类型必须匹配测试,否则将被标记为错误。对于regexAny,至少有一个测试必须匹配。对于regexAll,所有正则表达式测试都必须匹配。对于regexNone,不应匹配任何正则表达式测试。

$rules = [
    'first-name' => [
        'type' => 'text',
        'regexAll' => [
            //name must start with letter
            [
                'test' => '/^[a-z]/i',
                'err' => 'name must start with an alphabet'
            ],
            //only aphabets, dash and apostrophe is allowed in name
            [
                'test' => '/^[-a-z\']+$/',
                'err' => 'only aphabets, dash, and apostrophe is allowed in name'
            ]
        ]
    ],
    'country' => [
        'type' => 'text',
        'options' => [
            'regex' => [
                'test' => '/^[a-z]{2}$/',
                'err' => '{this} is not a 2-letter country iso-code name'
            ]
        ],
    ],
    'phone-number' => [
        'type' => 'text',
        'options' => [
            'regexAny' => [
                'tests' => [
                    //phone number can match nigeria mobile number format
                    '/^0[0-9]{3}[-\s]?[0-9]{3}[-\s]?[0-9]{4}$/',

                    //phone number can match uk mobile number format
                    '/^07[0-9]{3}[-\s]?[0-9]{6}$/'
                ],
                'err' => 'only nigeria and uk number formats are accepted'
            ]
        ]
    ],
    'favorite-colors' => [
        'options' => [
            'regexNone' => [
                //we dont accept white as a color
                [
                    'test' => '/^white$/i',
                    'err' => '{this} is not an acceptable color'
                ],
                //we dont accept black either
                [
                    'test' => '/^black$/i',
                    'err' => '{this} is not an acceptable color'
                ],
            ],
        ],
    ],
]

匹配规则验证

当您想确保字段值与另一个字段值匹配时,例如在密码确认字段以及电子邮件和电话确认场景中,此规则非常方便。

$rules = [
    'password1' => [
        'type' => 'password'
    ],
    'password2' => [
        'type' => 'password',
        'options' => [
            'matchWith' => '{password1}', //reference password1 value
            'err' => 'Passwords do not match'
        ],
    ],
];

日期验证

要验证日期,将类型属性设置为'date'。您可以指定验证日期是否在给定范围内的限制规则。

$rules = [
    'date-of-birth' => [
        'type' => 'date',
        'options' => [
            'min' => '01-01-1990', //only interested in people born on or after 01-01-1990
            'max' => '{CURRENT_DATE}'
        ]
    ],
];

范围验证

要将字段作为值范围进行验证,将类型属性设置为range。范围类型接受三个更多选项键,分别是from(起始值)、to(结束值)以及可选的step键,默认值为1。

$rules = [
    'day' => [
        'type' => 'range',
        'options' => [
            'from' => 1,
            'to' => 31,
        ],
    ],
    'month' => [
        'type' => 'range',
        'options' => [
            'from' => 1,
            'to' => 12,
        ],
    ],
    'year' => [
        'type' => 'range',
        'options' => [
            'from' => 1950,
            'to' => '{CURRENT_YEAR}',
        ],
    ],
    'even-number' => [
        'type' => 'range',
        'options' => [
            'from' => 0,
            'to' => 100,
            'step' => 2,
            'err' => '{this} is not a valid even number between 0-100'
        ],
    ]
];

选择验证

要将字段作为选项集进行验证,将类型属性设置为choice。可以使用choices属性指定可接受选项,该属性作为数组使用。该类型验证器内部使用此类型。

$rules = [
    'country' => [
        'type' => 'choice',
        'options' => [
            'choices' => array('ng', 'gb', 'us', 'ca', ...),// array of country codes,
            'err' => '{this} is not a valid country code'
        ],
    ],
];

电子邮件验证

要验证电子邮件地址,将类型属性设置为email

$rules = [
    'email' => [
        'type' => 'email'
    ],
];

URL验证

要验证URL,将类型属性设置为url

$rules = [
    'website' => [
        'type' => 'url'
    ],
];

数值验证

要验证数值,无论是浮点数还是整数,都定义了相应的验证类型。以下是一些类型:float(货币或数字)、positiveFloatpFloatnegativeFloatnFloatintegerintpositiveInteger(正整数)、negativeInteger(负整数)。

$rules = [
    'favorite-number' => [
        'type' => 'number'
    ],
    'user-id' => [
        'type' => 'positiveInt',
    ]
];

密码验证

密码类型验证类似于文本验证,除了添加了一些限制规则和正则表达式规则。默认验证实现是密码长度至少为8个字符,最大长度为28个字符。必须包含至少两个字母和至少两个非字母字符。如果您愿意,可以覆盖此默认设置。

[
    'min' => 8,
    'max' => 28,
    'regexAll' => [
        //password should contain at least two alphabets
        [
            'test' => '/[a-z].*[a-z]/i',
            'err' => 'Password must contain at least two letter alphabets'
        ],
        //password should contain at least two non letter alphabets
        [
            'test' => '/[^a-z].*[^a-z]/i',
            'err' => 'Password must contain at least two non letter alphabets'
        ],
    ],
];

文件验证

该模块可以验证文件,包括文件MIME类型的完整性。它提供广泛的文件验证类型,如图像、视频、音频、文档和存档。

准确识别文件大小单位,包括bytes(字节)、kb(千字节)、mb(兆字节)、gb(吉字节)和tb(太字节)。

$rules => [
    'picture' => [
        'type' => 'file',
        'options' => [
            'min' => '50kb' //it will be converted accurately
        ]
    ],
];

您可以使用 moveTo 选项定义绝对路径来移动文件。当文件正在处理时,会为其计算一个哈希名称,并存储在字段中,以便可以直接使用实例上的 getData() 实例方法访问。

use Forensic\Handler\Handler;

$move_to = getcwd() . '/storage/media/pictures';
$rules => [
    'picture' => [
        'type' => 'file',
        'options' => [
            'moveTo' => $move_to
        ],
    ],
];

$handler = new Handler('post', $rules);
$handler->execute();

if ($handler->succeeds())
{
    $file_name = $handler->picture; //the computed hash name is stored in the field
    $file_abs_path = $move_to . '/' . $file_name;
}

处理多值字段和文件

处理器可以处理多值字段和文件字段。字段值在处理后被存储在数组中。

示例:

$move_to = getcwd() . '/storage/media/pictures';
$rules => [
    'pictures' => [
        'type' => 'file',
        'options' => [
            'max' => '400kb',
            'moveTo' => $move_to
        ],
    ],
];

$handler = new Handler('post', $rules);
$handler->execute();

if ($handler->succeeds())
{
    array_walk(function($file_name) {
        /**
         * we walk through all the files, and do whatever we want.
        */
        $abs_path = $move_to . '/' . $file_name; // abs path of current file.

    }, $handler->pictures);
}

指定接受的文件Mimes扩展

您可以在验证过程中指定接受的Mime文件扩展。请注意,处理器有一个 FileExtensionDetector 模块,可以根据其第一个魔法字节检测文件扩展名,从而限制文件扩展名欺骗错误。请注意,当前文件魔法字节的列表仍在更新中,您可以向我们报告更多缺失的魔法字节代码来帮助我们。

要指定接受的Mimes,请使用 mimes 选项。

示例:

$move_to = getcwd() . '/storage/media/pictures';
$rules => [
    'pictures' => [
        'type' => 'file',
        'options' => [
            'max' => '400kb',
            'moveTo' => $move_to,
            'mimes' => array('jpeg', 'png') //we only accept jpeg and png files. no gif,
            'mimeErr' => 'we only accept jpeg and png images'
        ],
    ],
];

图像文件验证

验证图像文件的最简单方法是使用 image 类型选项。接受的图像Mimes包括 JPEGPNGGIF

$move_to = getcwd() . '/storage/media/pictures';
$rules => [
    'pictures' => [
        'type' => 'image',
        'options' => [
            'max' => '400kb',
            'moveTo' => $move_to,
        ],
    ],
];

音频文件验证

验证音频文件的最简单方法是使用 audio 类型选项。接受的音频Mimes包括 MP3 等。

$move_to = getcwd() . '/storage/media/audios';
$rules => [
    'pictures' => [
        'type' => 'audio',
        'options' => [
            'max' => '400mb',
            'moveTo' => $move_to,
        ],
    ],
];

视频文件验证

验证视频文件的最简单方法是使用 video 类型选项。接受的视频Mimes包括 MP4OGGMOVI 等。

$move_to = getcwd() . '/storage/media/videos';
$rules => [
    'pictures' => [
        'type' => 'video',
        'options' => [
            'max' => '400mb',
            'moveTo' => $move_to,
        ],
    ],
];

媒体文件验证

验证媒体文件(视频、图像和音频)的最简单方法是使用 media 类型选项。接受的Mimes是 videoimageaudio Mimes 的组合。

$move_to = getcwd() . '/storage/media';
$rules => [
    'pictures' => [
        'type' => 'media',
        'options' => [
            'max' => '400mb',
            'moveTo' => $move_to,
        ],
    ],
];

文档文件验证

验证文档文件的最简单方法是使用 document 类型选项。接受的文档Mimes包括 DOCXPDFDOC 等。

$move_to = getcwd() . '/storage/documents';
$rules => [
    'pictures' => [
        'type' => 'document',
        'options' => [
            'max' => '4mb',
            'moveTo' => $move_to,
        ],
    ],
];

存档文件验证

验证归档文件的最简单方法是使用 archive 类型选项。接受的归档Mimes包括 ZIPTAR.GZTAR 等。

$move_to = getcwd() . '/storage/archives';
$rules => [
    'pictures' => [
        'type' => 'archive',
        'options' => [
            'max' => '50mb',
            'moveTo' => $move_to,
        ],
    ],
];

如何实现DBCheckerAbstract接口

要启用数据库完整性检查,您必须在 DBCheckerAbstract 类上实现两个方法,即 buildQuery()execute() 方法。然后您必须将您具体类的实例作为 Handler 的第四个参数提供。

以下是如何在 Laravel 中实现此操作的示例

<?php
namespace app\Handler;

use Forensic\Handler\Abstracts\DBCheckerAbstract;
use Illuminate\Support\Facades\DB;

class DBChecker extends DBCheckerAbstract
{
    /**
     * construct query from the given options
     *
     *@param array $options - array of options
     * the options array contains the following fields.
     * 'entity': is the database table
     * 'params': which is array of parameters. defaults to empty array
     * 'query': which is the query to run. defaults to empty string
     *  'field': if the query parameter is empty string, then there is the field parameter
     * that refers to the database table column to check
    */
    protected function buildQuery(array $options): string
    {
        $query = $options['query'];

        //if the query is empty string, we build it according to our orm
        if ($query === '')
        {
            //build the query
            $query = 'SELECT * FROM ' . $options['entity'] . ' WHERE ' .
                $options['field'] . ' = ?';
        }
        return $query;
    }

    /**
     * executes the query. the execute method should return array of result or empty
     * array if there is no result
    */
    protected function execute(string $query, array $params, array $options): array
    {
        return DB::select($query, $params);
    }
}

然后我们可以定义我们自己的 BaseHandler 并将我们具体类的实例作为第四个参数提供给父构造函数,如下所示

//file BaseHandler
namespace app\Handler;

use Forensic\Handler\Handler as ParentHandler;

class BaseHandler extends ParentHandler
{
    public function construct($source = null, array $rules = null)
    {
        parent::__construct($source, $rules, null, new DBChecker());
    }
}

因此,我们现在可以使用如下的 'check' 和 'checks' 规则选项

// file AuthHandler.php

namespace app\Handler;

use app\Model\UserModel; //our model

class AuthHandler extends BaseHandler
{
    /**
     * executes signup
     *@param array|string [$source = 'post'] - the source of the data. can also be an array
    */
    public function executeSignup($source = 'post')
    {
        $rules = [
            //email field rule.
            'email' => [
                'type' => 'email',
                'err' => '{this} is not a valid email address',

                //db check rule goes here
                'check' => [
                    'if' => 'exists', // note that it is error if it exists
                    'entity' => 'users',
                    'field' => 'email',
                    'err' => 'User with email {this} already exists, login instead',
                ]
            ],
            'password1' => [
                'type' => 'password',
            ],
            'password2' => [
                'type' => 'password',
                'matchWith' => '{password1}'
            ],
        ];

        $this->setSource($source)->setRules($rules);

        if (!$this->execute())
            return $this->succeeds(); //return immediately if there are errors

        //create user
        $user = new UserModel();

        //do not copy password2 and rename password1 to just password
        $this->modelSkipField('password2')->modelRenameField('password1', 'password');
        $this->mapDataToModel($user)->save(); // it returns the model

        //set the new user id
        $this->setData('id', $user->id);

        return $this->succeeds();
    }
}

定义检查和检查完整性规则

check 选项定义单个数据库完整性检查,而 checks 选项定义数据库完整性检查的数组。

在定义规则时,可以选择编写要执行的select查询。在这种情况下,应该有一个 query 属性,如果需要,还有一个 params 数组属性(如果没有提供,则默认为空数组)。

第二种选择是在单个实体字段上执行检查。在这种情况下,应该有一个引用要从中选择的数据库表的 entity 属性,以及定义在where子句中使用的表列的 field 属性。如果省略了 field 属性,如果字段值是整数,则默认为 id,否则默认为解析的字段名(根据 modelCamelizeFields($status) 方法的状态,可以是驼峰式或蛇形命名)。

$rules = [
    'userid' => [
        'type' => 'positiveInt',
        'check' => [
            'if' => 'notExist',
            'entity' => 'users'
            //since no query is defined, the field option will default to id rather than
            // userid because the field value is an integer,

            //params options will default to array(current_field_value)
        ]
    ],
    'email' => [
        'type' => 'email',
        'checks' => [
            //first check
            [
                'if' => 'exists',
                'entity' => 'users'
                //since no field is defined, it will defualt to email
            ],
            //more checks goes here
        ]
    ],
    'country' => [
        'type' => 'text',
        'checks' => [
            //first check
            [
                'if' => 'notExist',
                'query' => 'SELECT * from countries WHERE value = ?',
                'params' => array('{this}'),
                'err' => '{this} is not recognised as a country in our database'
            ],
        ],
    ],
];

如何编写您的自定义验证类型

该模块旨在可扩展,以便您定义更多验证方法和使用自定义的规则类型。您需要了解一些关于模块工作方式的基本知识。检查 ValidatorInterfaceValidator 类文件是一个不错的起点。下面展示了如何轻松实现这一功能。

定义继承自主验证器的自定义验证器:

<?php
//file CustomValidator.php
namespace app\Handler;

use Forensic\Handler\Validator;

class CustomValidator extends Validator
{
    protected function validateName(bool $required, string $field, $value,
        array $options, int $index = 0): bool
    {
        $options['min'] = 3;
        $options['max'] = 15;
        $options['regexAll'] = [
            //only alphabets dash and apostrophe is allowed in names
            [
                'test' => '/^[-a-z\']$/i',
                'err' => 'only alphabets, hyphen and apostrophe allowed in names'
            ]
            //name must start with at least two alphabets
            [
                'test' => '/^[a-z]{2,}/i',
                'err' => 'name must start with at least two alphabets'
            ],
        ];
        return $this->validateText($required, $field, $value, $options, $index);
    }
}

然后我们可以定义自己的 BaseHandler,并集成新添加的 name 类型验证方法,如下所示

//file BaseHandler
namespace app\Handler;

use Forensic\Handler\Handler as ParentHandler;

class BaseHandler extends ParentHandler
{
    public function construct($source = null, array $rules = null)
    {
        parent::__construct($source, $rules, new CustomValidator(), new DBChecker());
    }

    /**
     *@override the parent method.
    */
    public function getRuleTypesMethodMap(): array
    {
        return array_merge(parent::getRuleTypesMethodMap(), [
            'name' => 'validateName'
        ]);
    }
}

从此以后,我们就可以使用 name 类型来验证名称,如下所示

// file ProfileHandler.php

namespace app\Handler;

use app\Model\UserModel; //our model

class ProfileHandler extends BaseHandler
{
    /**
     * updates user profile
     *@param array|string [$source = 'post'] - the source of the data. can also be an array
    */
    public function updateProfile($source = 'post')
    {
        $rules = [
            //email field rule.
            'id' => [
                'type' => 'positiveInteger',

                //db check rule goes here
                'check' => [
                    'if' => 'doesNotExist',
                    'entity' => 'users',
                    'err' => 'No user found with id {this}',
                ]
            ],
            'first-name' => [
                'type' => 'name',
            ],
            'last-name' => [
                'type' => 'name',
            ],
            'middle-name' => [
                'type' => 'name',
                'required' => false,
                'default' => ''
            ]
        ];
        //more codes below
    }
}

RequiredIf 或 RequireIf 选项

使用此选项,我们可以使一个字段在满足给定条件时成为必填项。这些条件包括

  1. 如果另一个字段被选中或未被选中

    $rules = [
        'is-current-work' => [
            'type' => 'boolean',
        ],
        'work-end-month' => [
            'type' => 'range',
            'options' => [
                'from' => 1,
                'to' => 12
            ],
            'requiredIf' => [
                'condition' => 'notChecked',
                'field' => 'is-current-work'
            ],
        ],
        'subscribe-newsletter' => [
            'type' => 'boolean'
        ],
        'email' => [
            'requiredIf' => [
                'condition' => 'checked',
                'field' => 'subscribe-newsletter'
            ],
        ],
    ];
  2. 如果另一个字段等于给定值或与其不相等

    $rules = [
        'country' => [
            'type' => 'choice',
            'options' => [
                'choices' => array('ng', 'us', 'gb', 'ca', 'gh')
            ],
        ],
        //if your country is not nigeria, tell us your country calling code
        'calling-code' => [
            'requiredIf' => [
                'condition' => 'notEquals',
                'value' => 'ng',
                'field' => 'country'
            ],
        ],
        //if you are in nigeria, you must tell us your salary demand
        'salary-demand' => [
            'requiredIf' => [
                'condition' => 'equals',
                'value' => 'ng',
                'field' => 'country'
            ],
        ],
    ];