【问题标题】:Best way to separate validation data分离验证数据的最佳方法
【发布时间】:2019-10-27 01:46:12
【问题描述】:

我的代码并没有真正的问题,更像是我的代码结构的问题。

我的项目是用 Laravel 编写的,我使用 laravel 为我们生成的资源控制器。在我的 Update() 函数中,我做了很多数据处理。

一些例子:

更新()

public function update(Request $request)
{

    $post = (object) $request->all();

    unset($post->XDEBUG_SESSION_START);

    $this->preparePassword($post);

    $this->prepareMail($post);

    $this->prepareAvailability($post);

    $this->prepareZip($post);

    $this->prepareSofttags($post);

    $user = User::find(Auth::id());

    $user->update((array) $post);
}

更新调用函数来处理数据。一些例子:

private function prepareAvailability(stdClass &$data) : void
{
    // If no days or a date is selected, return
    if (empty($data->available_days) && empty($data->available_from)) {
        return;
    }

    // when days are given (available)
    if ($data->available_days) {
        $days = (int) $data->available_days;
        $avail_level = 0.2 * $days;

        $data->avail_level = $avail_level;
        $data->avail_from = mysqldate(strtotime('today'), true);

        unset($data->available_days);
    }

    // When a date is given (no available)
    if ($data->available_from) {
        $data->avail_level = 0;
        $data->avail_from = mysqldate(strtotime($data->available_from), true);

        unset($data->available_from);
    }
}

和:

private function prepareZip(stdClass &$data) : void
{
    if (empty($data->zip)) {
        return;
    }

    $zip4d = (int) substr($data->zip, 0, 4);
    $zipData = Zip::check($zip4d);
    $data->city = $zipData->name;
}

我只是向您展示了 2 个功能,尽管我还有更多功能,而且还会有更多功能。现在我的控制器充满了私有函数,它们只是以多种方式处理数据。

有没有更好的方法,我在考虑特质,但特质应该与每个班级兼容。不特定于一个控制器。

有人对此有什么想法吗?

附:如果您不了解代码中使用的某些功能,例如“mysqldate”,我会使用一些辅助功能

【问题讨论】:

  • 听起来像是 en.wikipedia.org/wiki/Chain-of-responsibility_pattern 的用途。我发现有人在 Laravel 项目中使用它的 Medium 帖子:medium.com/@nikolakusibojoski/…。在某些 PHP 框架中,所有请求都通过这种类型的链进行处理。
  • 从我所看到的到我在整个职业生涯中必须处理的代码,整个代码布局都很可爱!我就是这样做的,所以我对这方面的任何改进都很感兴趣!
  • mysqldate(strtotime('today'), true); 可以替换为Carbon::now()->toDateString(); Carbon 是 Laravel 自带的,并且有很多日期函数,让事情变得更简单。
  • @Pockets 并感谢您的建议,但那些文章听起来像是他制造了一个问题,然后试图用一些奇怪的模式解决这个问题。 (这就是我的感受)。也许它的倒示例让我觉得“这不会发送任何发送”或我的倒英语。也许两者兼而有之:)
  • 您可以创建一个Request 对象,该对象甚至可以在请求数据到达您的控制器之前对其进行修改。这是一个不错的解决方案,因为它将您的操作逻辑放在一个中心位置,并保证您以您期望的方式接收数据。请参阅此示例 - stackoverflow.com/q/28854585/296555

标签: php laravel


【解决方案1】:

据我所知,您的控制器有很多职责,这通常意味着现在是拆分事情的好时机。我认为可以将以下内容提取到其他类中:

  1. 输入验证(检查数据是否存在)。例如available_days 是必填字段。为此可以使用laravel form request validation
  2. 数据验证(检查数据是否正确)。例如,邮政编码应该以数字和字母分开。为此,您可以像 example 这样为邮政编码引入值对象
  3. 域验证(包含您的问题域的规则)例如,如果没有给出available_from 日期,available_from 将是今天)。这些通常是确保它们不能处于无效状态的类(这意味着在构造它们之后总是完整的并且数据是有意义的)。它们通过在构造函数和修改它们包含的数据的其他方法中强制执行域规则来做到这一点。

作为奖励,当像这样拆分职责时,通常意味着(单元)测试会变得更容易。

如果您想了解更多信息,请告诉我。现在我只是快速写了一篇。

【讨论】:

  • 这个比较像。相当简单干净。感谢您的建议!
【解决方案2】:

根据建议,我开始使用 Laravel FormRequest 类/方法/概念

https://laravel.com/docs/5.8/validation#form-request-validation

我清理了我的代码,我的更新功能现在是一个“单行”,你可以看到它以前是一团糟。结果:

public function update(UpdateUserRequest $request)
{
    user()->update($request->all());
    // user() helper function short for Auth::user()
}

一点解释。我的 $request 不是 Request 类,而是 UpdateUserRequest 类:

update(UpdateUserRequest $request)

'php artisan make:request UpdateUserRequest'

这个类有一个函数叫

public function withValidator($validator)

这个函数在发出请求时触发,所以在它进入控制器逻辑之前,我在这个类中验证数据并重新分配 $request 值,就像我之前所做的那样。

最终结果:

public function withValidator()
{
    $post = (object) $this->all();
    // Update password if possible
    $this->preparePassword($post);
    // Update mail
    $this->prepareMail($post);
    // Update availability
    $this->prepareAvailability($post);
    //
    $this->prepareZip($post);
    //
    $this->prepareSofttags($post);

    $this->merge((array) $post);
}

所有调用的函数都是这个类中的私有函数。所以我把私有函数从控制器移到了这里,这样我的控制器就又干净了。

我将在此代码库中进行更多更改,因为现在我在每个私有函数中插入所有请求数据,但最好只插入我想要检查的数据并更改 $request ($this在这种情况下)直接在验证之后。所以我最后没有合并它。

附:我的英语不是很好,所以如果我有一些错别字或不太明白我在说什么,请问我。

附言 如果你看到任何我可以改进的地方,请不要退缩并告诉我:)

谢谢大家的建议!

【讨论】:

    猜你喜欢
    • 2011-08-30
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多