草庐IT

php - Laravel/PHP - 高级多态关系

coder 2024-04-19 原文

在我的网络应用程序中,用户可以将文档电子邮件上传到 channel

channel 还可以有 document_tagsemail_tags所有 上传的文档/电子邮件应该自动继承。

此外,document_tagsemail_tags有不同的描述:tag_descriptions。因此,例如,如果我们有一个文档,上传到具有标签的 channel :animals (id = 1)pets (id = 2)

  1. Document #55 已上传至 Channel #8
  2. Document #55 将自动继承具有 document_tags.channel_id = 55 的标签(这可以通过以下关系访问:$channel->文档标签)。在本例中是动物宠物
  3. 现在用户应该能够在 tag_descriptions 中为 animalspets 设置唯一的描述,例如:

tag_descriptions

id | taggable_type   | taggable_id  | typeable_type | typeable_id | description
1  | App\DocumentTag | 1            |  App\Document | 55          | My unique description for animals. 
2  | App\DocumentTag | 2            |  App\Document | 55          | My unique description for pets.

现在在上面的数据库设计中,上传的文件#55,有标签:animalspets相关联,但是这两个标签还有独特的描述,对于特定的文档是独一无二的。

如果我上传另一个文档或电子邮件(比如 email #20),那么我想它会是这样的:

tag_descriptions:

id | taggable_type   | taggable_id  | typeable_type | typeable_id | description
1  | App\DocumentTag | 1            |  App\Document | 55          | My unique description for animals. 
2  | App\DocumentTag | 2            |  App\Document | 55          | My unique description for pets.
3  | App\EmailTag    | 1            |  App\Email    | 20          | Another unique description for animals. 
4  | App\EmailTag    | 2            |  App\Email    | 20          | Yet another unique description for pets.

现在 email #20 也有标签 animalspets,但在这种情况下,用户可以为标签。

现在我的问题是:

以上设计是否可行,是否被认为是 Laravel/PHP 中的最佳实践?我有点不确定如何构建代码,因为 TagDescription 模型会突然有两个多态关系(taggabletypeable),我在文档中找不到任何支持它的内容。

此外,我不确定是否可以使用上述设计通过特定的上传文档访问唯一描述,例如:

//In my Document.php model:
public function tagdescriptions()
{
    return $this->morphMany(TagDescription::class, 'typeable');
}

然后像这样使用它:$document->tagdescriptions

最后但同样重要的是 - 我有点不确定如何为特定的 taggable_id/taggable_type 和独特的电子邮件/文档保存独特的标签描述。 (typeable_id 和 typeable_type)。

最佳答案

我不确定您到底想做什么,但是具有两个多态关系的表没有意义。启用多态关系的表是数据透视表。虽然我知道您想要每个标签和关系类型的唯一描述,但数据透视表应该只有两个外键列,一个表与和相关。
还有一种方法,就是利用多态关系作为对数据透视表的约束。首先,多态关系中的数据透视表应该重命名为“taggables”。您不需要“email_tag”表和“document_tag”表,您可以使用名为“tags”的表。要获得每个标签的唯一描述,您可以将描述添加到表“tabblables”。

迁移文件看起来像这样......

public function up()
{
    Schema::create('taggables', function (Blueprint $table) {
        $table->increments('id');
        $table->unsignedInteger('tag_id');
        $table->unsignedInteger('taggable_id');
        $table->string('taggable_type');
        $table->string('description');
        $table->timestamps();
    });

    Schema::create('tags', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });

    Schema::create('documents', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });

    Schema::create('emails', function (Blueprint $table) {
        $table->increments('id');
        $table->string('name');
        $table->timestamps();
    });
}

这里是您需要在电子邮件和文档模型中执行的操作。

class Email extends Model
{
    /**
     * Get all of the tags.
     */
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable')->withPivot('description');
    }
}

class Document extends Model
{
    /**
     * Get all of the tag descriptions.
     */
    public function tags()
    {
        return $this->morphToMany(Tag::class, 'taggable')->withPivot('description');
    }
}

“withPivot”函数将返回查询中指定列的值。

这是您需要在标签模型中执行的操作。

class Tag extends Model
{
    /**
     * Get all of the tag descriptions.
     */
    public function documents()
    {
        return $this->morphByMany(Document::class, 'taggable');
    }

    /**
     * Get all of the tag descriptions.
     */
    public function emails()
    {
        return $this->morphByMany(Email::class, 'taggable');
    }
}

您不需要“可标记”表模型。

事情是这样的。当你修补......

$email = App\Email::find(1)->tags;

此查询将运行...

select `tags`.*, 
    `taggables`.`taggable_id` as `pivot_taggable_id`, 
    `taggables`.`tag_id` as `pivot_tag_id`, 
    `taggables`.`taggable_type` as `pivot_taggable_type`, 
    `taggables`.`description` as `pivot_description` 
from `tags` 
inner join `taggables` on `tags`.`id` = `taggables`.`tag_id` 
where `taggables`.`taggable_id` = 1 
and `taggables`.`taggable_type` = 'App\Email'

你看到的是多态关系的约束可以查询唯一描述。总之,您不能在一个数据透视表中放置两个以上的外键关系,但您可以将约束添加到您的数据透视表。

我认为将这个添加到您的 AppServiceProvider.php 文件中看起来更干净...

public function boot()
{
    Relation::morphMap([
        'email'     => Email::class,
        'document'  => Document::class
    ]);
}

https://laravel.com/docs/5.8/eloquent-relationships#polymorphic-relationships

这将使您能够将“电子邮件”或“文档”的值存储为您的可标记类型。

对于发布到表格,我认为这看起来最干净...

$tag = Tag::firstOrNew(["name"=>"#tag"]);
$tag->name = "#tag";

$document = new Document();
$document->name = "new doc";
$document->save();
$document->tags()->save($tag,["description"=>"some description"]);

当然可以使用 attach()。 Save() 使用 attach() 如下所示... https://github.com/laravel/framework/blob/5.8/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php#L871

希望这对您有所帮助。

关于php - Laravel/PHP - 高级多态关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55816088/

有关php - Laravel/PHP - 高级多态关系的更多相关文章

  1. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

  2. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  3. ruby-on-rails - rails 多态关联(遗留数据库) - 2

    我使用的是遗留数据库,所以我无法控制数据模型。他们使用了很多多态链接/连接表,就像这样createtableperson(per_ident,name,...)createtableperson_links(per_ident,obj_name,obj_r_ident)createtablereport(rep_ident,name,...)其中obj_name是表名,obj_r_ident是标识符。因此链接的报告将按如下方式插入:insertintoperson(1,...)insertintoreport(1,...)insertintoreport(2,...)insertint

  4. ruby - Rails 组合多个 activerecord 关系 - 2

    我想合并多个事件记录关系例如,apple_companies=Company.where("namelike?","%apple%")banana_companies=Company.where("namelike?","%banana%")我想结合这两个关系。不是合并,合并是apple_companies.merge(banana_companies)=>Company.where("namelike?andnamelike?","%apple%","%banana%")我要Company.where("名字像?还是名字像?","%apple%","%banana%")之后,我会写代

  5. ruby-on-rails - Ruby on Rails - has_one 关系,如何检查它是否具有现有关联? - 2

    我有一个简单的问题,与关联有关。我有一个书的模型,它有_onereservation。预订属于_书本。我想在预订Controller的创建方法中确保在预订时没有预订一本书。换句话说,我需要检查该书是否存在任何其他预订。我该怎么做?编辑:Aaa我做到了,感谢大家的提示,学到了一些新东西。当我尝试提供的解决方案时,出现no_method错误或nil_class等。这让我开始思考,我尝试处理的对象根本不存在。Krule给了我使用book.find的想法,所以我尝试使用它。最终我得到了它的工作:book=Book.find_by_id(reservation_params[:book_id])

  6. ruby-on-rails - 这个 C 和 PHP 程序员如何学习 Ruby 和 Rails? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我来自C、php和bash背景,很容易学习,因为它们都有相同的C结构,我可以将其与我已经知道的联系起来。然后2年前我学了Python并且学得很好,Python对我来说比Ruby更容易学。然后从去年开始,我一直在尝试学习Ruby,然后是Rails,我承认,直到现在我还是学不会,讽刺的是那些打着简单易学的烙印,但是对于我这样一个老练的程序员来说,我只是无法将它

  7. ruby - 高级语言是否使用数据结构? - 2

    我目前还在上学,正在上一门关于用C++实现数据结构的类(class)。在业余时间,我喜欢使用“高级”语言(主要是Ruby和一些c#)进行编程。既然这些高级语言为你管理内存,你会用数据结构做什么?我可以理解对队列和堆栈的需求,但是您需要在Ruby中使用二叉树吗?还是2-3-4树?为什么?谢谢。 最佳答案 Sosincethesehigherlevellanguagesmanagethememoryforyou,whatwouldyouusedatastructuresfor?使用数据结构的主要原因与垃圾收集无关。但它是以某种方式有效的

  8. ruby-on-rails - Ruby/Rails - 检查 HABTM 关系记录中是否存在子 ID - 2

    我有一组名为Tasks和Posts的资源,它们之间存在has_and_belongs_to_many(HABTM)关系。还有一个连接它们的值的连接表。create_table'posts_tasks',:id=>falsedo|t|t.column:post_id,:integert.column:task_id,:integerend所以我的问题是如何检查特定任务的ID是否存在于从@post.tasks创建的数组中?irb(main):011:0>@post=Post.find(1)=>#@post.tasks=>[#,#]所以我的问题是,@post.tasks中是否存在"@task

  9. Ruby On Rails 模型、 View 和 Controller 之间的关系 - 2

    根据我目前的理解,如果我必须描述Rails应用程序的各个组件如何协同工作以响应请求,我会说以下内容:1)路由确定哪些请求URL映射到哪些Controller方法。2)Controller方法从模型中获取信息并将该信息(以全局变量的形式)传递给相应的View模板。3)View模板使用存储在全局变量中的数据来构造最终响应。在上面的解释中,几个组件之间的关系是明确的,不可否认的;即:1)路由和Controller方法2)Controller方法和View模板其实上面的关系是一对一的。但是,模型类与其相邻组件类型(即Controller)的关系并不明确。是的,Controller从模型中检索信

  10. ruby - ActiveRecord,通过多态属性查找 - 2

    有这个:classEventtrueenduser=User.create!我可以:Event.create!(:historizable=>user)但我不能:Event.where(:historizable=>user)#Mysql2::Error:Unknowncolumn'events.historizable'in'whereclause'我必须改为这样做:Event.where(:historizable_id=>user.id,:historizable_type=>user.class.name)更新重现问题的代码:https://gist.github.com/fg

随机推荐