【问题标题】:Laravel 5 custom validation rule for existing tagsLaravel 5 现有标签的自定义验证规则
【发布时间】:2015-06-14 19:06:39
【问题描述】:

我正在寻找一种更简洁的方法来在存储帖子时验证标签。

所有输入验证都在我的自定义请求StorePostRequest 中进行。问题是我需要检查数据库中是否存在给定的标签,只允许现有的标签。函数$request->input('tags')返回一个以逗号分隔的字符串,例如:Tag1,Tag2,Tag3

代码如下:

/**
 * Store a newly created resource in storage.
 *
 * @param  StorePostRequest $request
 * @return Response
 */
public function store(StorePostRequest $request)
{
    //THIS PIECE OF CODE
    $tags = explode(',', $request->input('tags'));
    $tags = Tag::whereIn('title', $tags)->lists('id');

    if(count($tags) < 1)
    {
        return redirect()->back()->withInput()->withErrors([ trans('tags.min') ]);
    }
    else if(count($tags) > 5)
    {
        return redirect()->back()->withInput()->withErrors([ trans('tags.max') ]);
    }
    //TILL HERE

    $post = $request->user()->posts()->create([
        'slug'          => unique_slug('Post', $request->input('title')),
        'title'         => $request->input('title'),
        'description'   => $request->input('description'),
        'summary'       => $request->input('summary'),
    ]);

    $post->tags()->attach($tags);

    return redirect(route('theme.post.show', [$theme->slug, $post->slug]))->with(['success', trans('messages.post.store')]);
}

在多个控制器中使用时,代码有点草率和冗余。

为了解决这个问题,我创建了一个ValidationServiceProvider 来扩展核心验证器规则。像这样的:

$this->app['validator']->extend('tags', function ($attribute, $value, $parameters)
{
    $tags = explode(',', $value);
    $tags = Tag::whereIn('title', $tags)->lists('id');

    if(count($tags) < 1 || count($tags) > 5))
    {
        return false;
    }
});

相当整洁。问题是我仍然需要能够访问控制器中的$tags 变量(因为-&gt;attach($tags))。

有没有更好的方法来解决这个问题?还是我应该停止思考,只使用(并重复)我拥有的代码?

提前致谢,希望能有所帮助。

【问题讨论】:

  • 您可以创建一个TagsTransformer 类来处理从字符串到数组的转换,并在控制器和验证器上使用它。
  • 是的,非常好。我现在在我的控制器中有一个名为processTags() 的私有函数,它执行标签的转换和验证。已经好多了。

标签: php validation laravel customization laravel-5


【解决方案1】:

我假设你了解这个类的用法,因为我看到你已经定义了StorePostRequest 类。因此,为了澄清起见,rules 方法可能如下所示:

public function rules()
{
    return [
        'tags' => ['required', 'tags'] //kb
    ];
}

最后,将所有工具放置在正确位置后,您只需像这样操作控制器中的数据:

public function store(StorePostRequest $request)
{
    // at this point, the tags are already validated, so we, proceed get them:
    $tags = explode(',', $$request->get('tags'));

    $post = $request->user()->posts()->create([
        'slug'          => unique_slug('Post', $request->input('title')),
        'title'         => $request->input('title'),
        'description'   => $request->input('description'),
        'summary'       => $request->input('summary'),
    ]);

    $post->tags()->attach($tags);

    return redirect(route('theme.post.show', [$theme->slug, $post->slug]))->with(['success', trans('messages.post.store')]);
}

请记住,在控制器的函数中注入 StorePostRequeststore 已经在验证和运行规则。

如果您确实正确定义了 StorePostRequest 的规则,这就足够了。

【讨论】:

  • 是的,规则运行良好。问题是我需要分解标签字符串,检查它们是否存在于数据库中,返回一个列表(id 数组)然后计数。所以我不能只使用tags =&gt; 'required|array|min:1|max:5'. 之类的规则。另外,$request-&gt;input('tags') 返回一个逗号分隔的字符串,所以我不能在我的控制器中使用 attach() 。如果我弄错了,请原谅:)
  • 我觉得你太复杂了。 tags 规则已经验证了计数的存在。为什么不把$tags = explode(',', $tags); 放在-&gt;attach($tags); 电话之前?查看已编辑的答案
  • $request-&gt;input('tags') 返回一个类似Tag1, Tag2, Tag3 的字符串。我必须首先在数据库中找到具有该标题的标签,在列表中获取它们的 ID,然后才能使用 -&gt;attach($tag_ids)
【解决方案2】:
foreach($request->tags as $k=>$tags){
            $this->validate($request, [
                'tags.'.$k => 'required|string|max:20'
            ]);
        }

【讨论】:

    猜你喜欢
    • 2015-01-26
    • 2017-04-11
    • 2018-02-18
    • 2015-06-02
    • 2015-09-07
    • 2019-02-12
    • 2016-11-22
    • 2019-03-17
    • 1970-01-01
    相关资源
    最近更新 更多