【问题标题】:Laravel Polymorphic Relations commentable_type validationLaravel 多态关系 commentable_type 验证
【发布时间】:2017-06-17 04:10:17
【问题描述】:

我正在使用 REST API 来接收数据。
数据模型与多态相关,类似于文档中的模型:
https://laravel.com/docs/5.4/eloquent-relationships#polymorphic-relations

posts
    id - integer
    title - string
    body - text

videos
    id - integer
    title - string
    url - string

comments
    id - integer
    body - text
    commentable_id - integer
    commentable_type - string

假设,例如,API 正在接收这条新评论:

{
    "body": "This a test comment",
    "commentable_type": "posts",
    "commentable_id": "1"
}

如何验证收到的 commentable_type 是否存在且有效?

【问题讨论】:

    标签: php laravel eloquent


    【解决方案1】:

    编辑

    我第一次可能误会了。如果您想检查保存在commentable_type 中的模型是否存在,您可以执行以下操作:

    $type = $comment->commentable_type;
    if(class_exists($type)) echo "it exists";
    

    根据您的需要,您可以对其inheritance 进行额外检查(例如,它扩展了Model 类)。或者其他真正符合您需求的东西。

    编辑2

    如果我是你,我会这样做。我会将属性protected $allRelations 添加到您的Comment 模型中并手动将所有关系放入其中。然后制作一些辅助模型来检查它是否在数组中。

    简单示例:

    <?php
    
    namespace App;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Comment extends Model
    {
        // ..
    
        protected $allRelations= [
            'posts' => '\App\Post',
            'videos' => '\App\Video',
        ];
    
        public static function validateRelationNs($ns) {
            return in_array($ns, $this->allRelations);
        }
    
        public static function validateRelationName($name) {
            return array_key_exists($name, $this->allRelations);
        }
    
        // ...
    }
    

    旧答案:

    Laravel 期望多态类型列的模型的完整命名空间名称(在您的情况下,commentable_type 应该是 \Full\Ns\Post,而不是 posts)。

    确保正确性的最简单方法是始终将其保存through the relationship。例如:

    $post = Post::first();
    $comment = new Comment($attributes);
    $post->comments()->save($comment).
    

    这将自动正确设置commentable_idcommentable_type(假设您的关系定义正确)。

    额外检查

    除此之外,您可以通过模型events 进行检查。您可以在保存到数据库之前对其进行验证。

    【讨论】:

    • 我认为在尝试插入数据库之前应该验证数据。在验证阶段以某种方式获取与 cmets 模型相关的所有模型。
    • 哦,所以你想在收到已经保存评论的json后检查模型是否真的存在?我第一次误会了。
    • 不完全是,我想检查模型是否存在并且与评论模型相关,在这种情况下是多态的。
    • 我的意思是多态关系的全部意义在于它可以属于任何类。所以我不明白“并且与多态相关”部分。您可以使用我更新的答案检查模型是否存在。
    • 为了存在可注释的关系,您必须声明如下内容: return $this->morphMany('App\Comment', 'commentable');在每个可以有 cmets 的模型中。我正在寻找的是一种确定 commentable_type 参数是否是有效模型并且与 cmets 模型相关的方法。
    【解决方案2】:

    如果我正确理解您的问题,您正在尝试验证给定的commentable_typecommentable_id 的多态关系对象是否存在。

    如果是这种情况,则没有现有的验证规则可以这样做,但您可以创建一个。
    基于the documentation,您可以执行以下操作:

    首先,在服务提供者的boot方法中添加新规则(例如AppServiceProvider):

    Validator::extend('poly_exists', function ($attribute, $value, $parameters, $validator) {
        if (!$objectType = array_get($validator->getData(), $parameters[0], false)) {
            return false;
        }
    
        return !empty(resolve($objectType)->find($value));
    });
    

    这就是你将如何使用它:

    'commentable_id' => 'required|poly_exists:commentable_type
    

    规则的作用是尝试从输入值中获取可注释类型(基于传递给规则的参数,在我们的例子中为commentable_type),然后解析对象并尝试查找记录对于给定的 ID ($value)。

    但请注意,要使其正常工作,commentable_type 的值必须是完全限定的类名(例如 App\Models\Post)。

    希望这会有所帮助!

    【讨论】:

    • 我有完全相同的问题,并尝试使用您的 sn-p 但无法使其正常工作,所以不确定我做错了什么。如果我放弃验证规则,那么它当然可以正常工作,但是当我将其添加回 FormRequest 时,我收到错误“需要可评论的 id 字段。”
    • @seekay 似乎在您的输入中找不到 commentable_id 字段。您能否向我展示您尝试提出的示例请求?
    • 这是一个gist - 我认为原因是我正在使用路由模型绑定。我想如果我在表单中包含一个带有commentable_id 的隐藏字段,它会起作用,但这似乎很老套。想法/建议?如果更容易的话,我可以打开一个单独的问题。
    • @seekay 我明白了,您的情况与作者的情况完全不同。但是既然你的Task对象已经通过模型绑定解析了,而且这个Task对象其实就是多态关系的模型,不是已经验证了吗?
    • 在我看来,情况相似,即我需要能够验证 commentable_id。话虽如此,我猜您是正确的,因为由于路由模型绑定,Task 对象会自动验证(否则 Laravel 会抛出错误)。谢谢!
    【解决方案3】:

    我的最终版本适用于验证类型和 id:

    Validator::extend('poly_exists', function ($attribute, $value, $parameters, $validator) {
        if (!$objectType = array_get($validator->getData(), $parameters[0], false)) {
            return false;
        }
    
        if (!class_exists($objectType)) {
            return false;
        }
    
        return !empty(resolve($objectType)->find($value));
    });
    

    【讨论】:

      【解决方案4】:

      包含变形图的更好方法:

          Validator::extend('poly_exists', function ($attribute, $value, $parameters, $validator) {
              if (! $type = array_get($validator->getData(), $parameters[0], false)) {
                  return false;
              }
      
              if (Relation::getMorphedModel($type)) {
                  $type = Relation::getMorphedModel($type);
              }
      
              if (! class_exists($type)) {
                  return false;
              }
      
              return ! empty(resolve($type)->find($value));
          });
      

      【讨论】:

        【解决方案5】:

        您可以在请求类中动态定义model_exists 规则。像这样的:

        public function rules()
        {
            $polymorphExistsRule = '';
            if ($this->has('commentable_type')) {
                $polymorphExistsRule .= '|exists:' . $this->commentable_type . ',id';
            }
        
            return [
                'commentable_type' => 'required_with:commentable_id',
                'commentable_id'   => 'required_with:commentable_type' . $polymorphExistsRule,
            ];
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-07-31
          • 2017-05-13
          • 2016-05-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-28
          相关资源
          最近更新 更多