下面這段代碼是Laravel自帶的表單驗證的語法,不太瞭解的能夠先查看文檔php
'group_num' => 'min:1|max:21' // 也可使用between替換min和max
咱們指望的結果是能校驗group_num
字段最小值是1,最大值是21laravel
but !!!數組
...單元測試
當我單元測試的時候發現,居然校驗經過了!測試
// 單元測試代碼 $warehouseId = 1; $prods = [ [ 'prod_id' => 1, 'group_num' => 111, 'location' => 1, ] ]; $warehouseLogic = new WarehouseLogic(); $result = $warehouseLogic->addProds($warehouseId, $prods); $this->assertEquals(ErrSvc::ERR_OK, $result['code']);
咱們看一下文檔ui
min:value驗證中的字段必須具備最小值。字符串、數字、數組或是文件大小的計算方式都用 size 方法進行評估。this
文章提到數字使用size方法進行評估,咱們看一下size
方法的文檔spa
size:value驗證的字段必須具備與給定值匹配的大小。對於字符串來講,value 對應於字符數。對於數字來講,value 對應於給定的整數值。對於數組來講,
size 對應的是數組的 count 值。對文件來講,size 對應的是文件大小(單位 kb )。code
文檔一切正常,咱們翻一翻代碼試着分析下緣由blog
咱們找到驗證類的文件並打開:\vendor\laravel\framework\src\Illuminate\Validation\Validator.php
大約在1180行,咱們看到validateMin()
方法
第一行代碼,是對參數個數進行驗證的,能夠pass掉第二行代碼,調用了getSize()方法,並對getSize()返回結果直接進行大小比較,問題頗有可能就出如今getSize()方法身上
咱們看一下getSize()的代碼
咱們能夠看到if裏面判斷了若是值是數字類型
而且$hasNumeric
就直接返回原始值,若是返回原始值的話,validateMin()
方法應該會正確校驗,因此if條件應該是不成立
的
緣由極可能就在$hasNumeric這個變量上
$hasNumeric調用了$this->hasRule($attribute
,$this->numericRules
)方法,並傳了兩個參數過去
$attribute
:當前屬性名
$this->numericRules
:['Numeric', 'Integer']
而後咱們看一下$this->hasRule()
方法究竟作了什麼?
hasRule方法直接調用了$this->getRule()
方法,而且將參數原封不動傳遞過去
咱們看一下getRule()方法幹了什麼?
咱們已知$attribute
是當前字段名,好比文章舉例用的字段group_num
$this->rules
其實就是字段+校驗規則拼裝的數組,格式以下:
既然第一個if語句的兩個變量都知道了,咱們就能判斷出第一個條件是不成立的,咱們繼續看接下來的代碼
代碼是對當前須要校驗字段的規則進行遍歷,而且格式化
list($rule, $parameters) = $this->parseRule($rule);假設是上圖中的group_num字段,他有3個校驗規則,分別是:required、min、max
第一次循環
$rule就是Required,$parameters爲空
第二次循環
$rule就是Min,$parameters就是[1]
咱們會發現parseRule($rule)
後,會對規則進行in_array的判斷,$rules
是參數(['Numeric', 'Integer'])上文有寫
假設咱們此時的字段是group_num:第一個規則是required,條件不成立;
第二個規則是Min,條件依然不成立;
第三個規則是Max,條件仍是不成立!
getRule()返回值:條件都不成立,方法走完,沒有任何返回值,返回值爲null
hasRule()返回值:回到hasRule()方法,會對getRule()方法值進行is_null(),並進行邏輯非處理(!),因此返回值爲false
咱們接着回到getSize()
方法,此時咱們就知道$hasNumeric
的值是false
因此下面的if條件都不成立
,最後Laravel使用mb_strlen()
對咱們數字類型的值進行了長度計算!!!
既然咱們知道緣由在於Laravel對當前字段全部規則進行了in_array($rule, ['Numeric', 'Integer'])
因此解決思路就是,若是咱們要對字段進行大小進行範圍校驗,咱們須要把規則修改爲:
'group_num' => 'integer|min:1|max:21'
因此文章開頭的校驗,對於數值類型的字段,是錯誤的!
其實這不是一個BUG,單純的是Laravel的校驗機制,不過Laravel文檔寫的很模糊!
因此你們在開發的時候記得必定要認真測試
!
原文在本身的博客:Laravel一次單元測試發現的’BUG’,分析並解決問題 - 木魚博客