为什么自定义规则不起作用? (允许用户仅为一种注册类型选择数量)

时间:2018-07-30 10:45:11

标签: php laravel

我有一个选择菜单供用户选择每种的数量 他想要的注册类型。

<form method="post" action="{{route('conferences.storeQuantities', 
['id' => $conference->id, 'slug' => $conference->slug])}}">
    <ul class="list-group">
        {{ csrf_field() }}
        @foreach($registration_types as $rtype)
        <li>
            <select id="rtype_{{ $rtype->id }}" 
                    data-price="{{ $rtype->price }}"
                    name="rtypes[{{ $rtype->name }}]">
                <option value="0">0</option>
                @for ($i = $rtype->min_participants; $i <= $rtype-> max_participants; $i++)
                    <option value="{{ $i }}">{{ $i }}</option>
                @endfor
            </select>
        </li>
       @endforeach
    </ul>
</form>

但是此字段有一些验证规则无法正常工作。基本上,有四件事需要验证:

  • 该字段为必填项
  • 用户引入的数量应介于min_participants和max_participants之间(min_participants和max_participants是registration_types表中的列,表示用户可以为特定注册选择的最小和最大数量)
  • 用户至少需要为会议中可用的注册类型选择数量,对于其他注册类型,应选择“ 0”
  • 但是用户不能为会议中所有可用的注册类型引入数量“ 0”

问题:但它无法正常工作,例如,如果用户为注册类型“常规”选择数量“ 1”,而为注册类型“加号”选择“ 0”,则显示验证message()规则的RegistrationTypeQuantity中定义的错误。但是用户应该只能为1种注册类型选择数量。

你知道如何解决吗?

storeQuantities()中使用的RegistrationTypeQuantity规则基本上是对数量求和,然后检查数量是否大于0:

 public function passes($attribute, $value)
    {

        $quantity = 0;

        foreach($value as $key=>$v) {

            if ( is_null($v)) return false;

            $rtype = RegistrationType::where('name',$key)->first();
            if ( ! $rtype) return false;

            // $rtype was found
            if ( ($v < $rtype->min_participants || $v > $rtype->max_participants) )
                return false;
        }

        // track total quantity selected
        $quantity += (int)$v;

        // make sure there was at least one purchase
        if ($quantity === 0) {
            return false;
        }

        return true;
    }

用户为每种注册类型存储所选数量的方法

 public function storeQuantities(Request $request, $id, $slug = null)
 {
     $request->validate([
        'rtypes' => ['required', 'array', new RegistrationTypeQuantity],
    ]);
        if ($validator->fails())
    {
        return redirect()->back()->withErrors($validator, 'quantitiesError');
    }

    $rtypeQuantities = $request->get('rtypes');
    $total = 0;
    $selectedRtypes = [];


    foreach ($rtypeQuantities as $rtypeName => $quantity) {
        if ($quantity) {
            $rtype = RegistrationType::where('name', $rtypeName)->firstOrFail();

            //dd($rtype);
            $price = $rtype->price;

            $selectedRtypes[$rtype->name]['quantity'] = $quantity;
            $selectedRtypes[$rtype->name]['price'] = $price;
            $selectedRtypes[$rtype->name]['subtotal'] = $price * $quantity;
            $total += $selectedRtypes[$rtype->name]['subtotal'];
            $selectedRtypes[$rtype->name]['total'] = $total;

            $selectedRtypes[$rtype->name]['questions'] = $rtype->questions;
            $selectedRtypes[$rtype->name]['id'] = $rtype->id;
        }
    }
    if($selectedRtypes){
        Session::put('selectedRtypes', $selectedRtypes);
        Session::put('customQuestions', $selectedRtypes[$rtype->name]['questions']);
        Session::put('total', $total);
    }
    return redirect(route('conferences.registration', ['id' => $id, 'slug' => $slug]));
     }
 }

选择菜单的HTML以选择数量:

<div class="card">
  <div class="card-header d-flex justify-content-between">
    <span>Registration Type</span>
    <span>Quantity</span>
    <span>Price</span>
  </div>
  <div class="card_body">
    <form method="post"
          action="https://proj.test/conference/1/conference-test/registration">

      <ul class="list-group list-group-flush">
        <input type="hidden" name="_token" value="">
        <li class="list-group-item d-flex align-items-center justify-content-between">
          <div class="w-100 text-truncate">
            <span>general</span>
          </div>
          <select class="custom-select form-control rtype_name" id="rtype_1"
                  data-price="5"
                  name="rtypes[geral]">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
          </select>
          <span>X 5.00€</span>
        </li>
        <li class="list-group-item d-flex align-items-center justify-content-between">
          <div class="w-100 text-truncate">
            <span>plus</span>
          </div>
          <select class="custom-select form-control rtype_name" id="rtype_3"
                  data-price="10"
                  name="rtypes[plus]">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
          </select>
          <span>X 10.00€</span>
        </li>
      </ul>
    </form>
  </div>
</div> 

验证规则有更好的解释:

如果有两种与会议相关联的注册类型(常规和加号),则注册类型“常规”的列“ min_participants”为“ 1”,max_participants列为“ 1”,注册类型“ plus”具有列“ min_participants”为“ 1”,max_participants为“ 2”。

  • 如果用户在选择菜单中单击“下一步”,注册类型为“常规”的数量为“ 0”,注册类型为“加号”的数量为“ 0”,则应失败因为用户需要至少选择一种注册类型的数量,因为注册需要关联一些注册类型

  • 如果用户在选择菜单中单击“下一步”,注册类型为“常规”的数量为“ 2”,注册类型为“加号”的数量为“ 0”,则应失败因为“一般”的“ max_participants”为“ 1”,并且用户选择了数量“ 2”(例如,在源代码中引入了2,因为在选择菜单2中不应为一般注册类型显示,而仅应在1和1)

  • 如果用户在选择菜单中单击“下一步”,注册类型为“常规”的数量为“ 1”,注册类型为“加号”的数量为“ 1”,则应通过

  • 如果用户在选择菜单中单击“下一步”,注册类型为“常规”的数量为“ 1”,注册类型为“加号”的数量为“ 0”,则应通过因为应该允许用户进行注册,而没有为所有注册类型选择数量,因为用户可能只想以注册类型“常规”进行注册,而不希望以注册类型“加号”进行注册。因此,对于用户为所有注册类型选择数量,它不是强制性的。

2 个答案:

答案 0 :(得分:0)

我没有查看所有详细信息,但是对我来说问题出在这里:

public function passes($attribute, $value)
{
    foreach($value as $key=>$v) {

        $quantity = 0;

您在每次迭代中将数量设置为0。也许你应该这样做

public function passes($attribute, $value)
{
    $quantity = 0;

    foreach($value as $key=>$v) {

因此,在开始循环之前,应使用0初始化此变量。

答案 1 :(得分:0)

根据discussion that took place和对current vs desired validation results的分析。

遵循验证规则的工作代码:

public function passes($attribute, $value)
{
    // we get the products quantity
    $count = array_sum($value);

    // FAIL in advance if no products were selected
    if($count == 0){
      return false;
    }

    foreach($value as $key=>$v) {

        $rtype = RegistrationType::where('name',$key)->first();
        if ( !$rtype ){
          return false;
        }

        // Only if at least one product was selected, test against DB params
        if ( $v != 0 && ($v < $rtype->min_participants || $v > $rtype->max_participants) ){
          return false;
        }
    }

    // If no rejectig conditions were found, validation should PASS
    return true;
}