搜尋
首頁後端開發php教程重新引入雄辯的多態關係

Re-Introducing Eloquent's Polymorphic Relationships

核心要點

  • Laravel的多態關聯允許一個模型在一個關聯上屬於多個其他模型。這簡化了數據庫結構,使代碼更易維護,並允許更動態和靈活的數據關係。
  • 在Laravel中設置多態關聯涉及在Eloquent模型中定義關聯。 morphTo方法用於接收多態關聯的模型,而morphManymorphOne方法用於與其他模型關聯的模型。
  • Laravel的MorphMap方法可用於指示Eloquent對每個模型使用自定義名稱,而不是類名。這在模型命名空間更改或命名空間過長的情況下很有幫助。
  • Laravel支持多對多多態關係,允許一個模型在多對多的基礎上屬於多個模型。這在復雜的應用程序中特別有用。

本文由Younes Rafie同行評審。感謝所有SitePoint的同行評審者,使SitePoint的內容盡善盡美!


Re-Introducing Eloquent's Polymorphic Relationships

您可能已經使用了模型或數據庫表之間不同類型的關係,例如Laravel中常見的:一對一、一對多、多對多以及has-many-through。但還有一種不太常見的類型:多態關聯。那麼什麼是多態關聯呢?

多態關聯是指一個模型在一個關聯上可以屬於多個其他模型。

為了闡明這一點,讓我們創建一個虛構的場景,其中我們有Topic和Post模型。用戶可以在主題和帖子中留下評論。使用多態關係,我們可以對這兩種情況使用單個comments表。令人驚訝,對吧?這似乎有點不切實際,因為理想情況下,我們必須創建post_comments表和topic_comments表來區分評論。使用多態關係,我們不需要兩個表。讓我們通過一個實際示例來了解多態關係。

我們將構建的內容

我們將創建一個演示音樂應用程序,其中包含歌曲和專輯。在這個應用程序中,我們可以對歌曲和專輯進行點贊。使用多態關係,我們將對這兩種情況使用單個upvotes表。首先,讓我們檢查構建此關係所需的表結構:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>

讓我們討論一下upvoteable_idupvoteable_type列,對於那些以前沒有使用過多態關係的人來說,這些列可能看起來有點陌生。 upvoteable_id列將包含專輯或歌曲的ID值,而upvoteable_type列將包含擁有模型的類名。 upvoteable_type列是ORM在訪問upvoteable關係時確定要返回哪個“類型”擁有模型的方式。

生成模型以及遷移

我假設您已經擁有一個正在運行的Laravel應用程序。如果沒有,這個高級快速入門課程可能會有所幫助。讓我們首先創建三個模型和遷移,然後編輯遷移以滿足我們的需求。

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>

請注意,在創建模型時傳遞-m標誌也會生成與這些模型關聯的遷移。讓我們調整這些遷移中的up方法以獲得所需的表結構:

{some_timestamp}_create_albums_table.php

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>

{some_timestamp}_create_songs_table.php

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

{some_timestamp}_create_upvotes_table.php

public function up()
{
    Schema::create('songs', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->integer('album_id')->unsigned()->index();
        $table->timestamps();

        $table->foreign('album_id')->references('id')->on('albums')->onDelete('cascade');
    });
}

現在,我們可以運行artisan migrate命令來創建這三個表:

public function up()
{
    Schema::create('upvotes', function (Blueprint $table) {
        $table->increments('id');
        $table->morphs('upvoteable'); // 添加无符号整数 upvoteable_id 和字符串 upvoteable_type
        $table->timestamps();
    });
}

現在讓我們配置我們的模型以注意專輯、歌曲和點讚之間的多態關係:

app/Upvote.php

<code>php artisan migrate</code>

app/Album.php

[...]
class Upvote extends Model
{
    /**
     * 获取所有拥有模型。
     */
    public function upvoteable()
    {
        return $this->morphTo();
    }
}

app/Song.php

class Album extends Model
{
    protected $fillable = ['name'];

    public function songs()
    {
        return $this->hasMany(Song::class);
    }

    public function upvotes()
    {
        return $this->morphMany(Upvote::class, 'upvoteable');
    }
}

Album和Song模型中的upvotes方法定義了這些模型和Upvote模型之間的多態一對多關係,並將幫助我們獲取該特定模型實例的所有點贊。

定義了關係後,我們現在可以試用該應用程序,以便更好地了解多態關係的工作原理。我們不會為此應用程序創建任何視圖,我們只會從控制台試用我們的應用程序。

如果您考慮控制器以及我們應該放置點贊方法的位置,我建議創建一個AlbumUpvoteController和一個SongUpvoteController。通過這種方式,我們在處理多態關係時,可以將事情嚴格地與我們正在操作的對象聯繫起來。在我們的例子中,我們可以對專輯和歌曲進行點贊。點贊不屬於專輯,也不屬於歌曲。此外,它不是一般的點贊,這與我們在大多數一對多關係中擁有UpvotesController的方式相反。希望這說得通。

讓我們啟動控制台:

class Song extends Model
{
    protected $fillable = ['title', 'album_id'];

    public function album()
    {
        return $this->belongsTo(Album::class);
    }

    public function upvotes()
    {
        return $this->morphMany(Upvote::class, 'upvoteable');
    }
}

檢索關係

現在我們已經準備好了一些數據,我們可以通過我們的模型訪問我們的關係。以下是upvotes表中數據的屏幕截圖:

Re-Introducing Eloquent's Polymorphic Relationships

要訪問專輯的所有點贊,我們可以使用upvotes動態屬性:

<code>php artisan tinker
>>> $album = App\Album::create(['name' => 'More Life']);
>>> $song = App\Song::create(['title' => 'Free smoke', 'album_id' => 1]);
>>> $upvote1 = new App\Upvote;
>>> $upvote2 = new App\Upvote;
>>> $upvote3 = new App\Upvote;
>>> $album->upvotes()->save($upvote1);
>>> $song->upvotes()->save($upvote2);
>>> $album->upvotes()->save($upvote3);</code>

也可以通過訪問執行對morphTo的調用的方法的名稱,從多態模型檢索多態關係的所有者。在我們的例子中,那是Upvote模型上的upvoteable方法。因此,我們將訪問該方法作為動態屬性:

$album = App\Album::find(1);
$upvotes = $album->upvotes;
$upvotescount = $album->upvotes->count();

Upvote模型上的upvoteable關係將返回一個Album實例,因為此點贊由Album實例的實例擁有。

由於可以獲取歌曲或專輯的點贊數量,因此我們可以根據視圖上的點贊對歌曲或專輯進行排序。這就是音樂排行榜的工作方式。

對於歌曲,我們將像這樣獲取點贊:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>

自定義多態類型

默認情況下,Laravel將使用完全限定的類名來存儲相關模型的類型。例如,在上面的示例中,Upvote可能屬於Album或Song,默認的upvoteable_type分別為App\AlbumApp\Song

但是,這有一個很大的缺陷。如果Album模型的命名空間發生更改怎麼辦?我們將不得不進行某種遷移以重命名upvotes表中的所有出現。這有點棘手!如果命名空間很長(例如App\Models\Data\Topics\Something\SomethingElse)會發生什麼?這意味著我們必須在列上設置一個很長的最大長度。這就是MorphMap方法可以幫助我們的地方。

“morphMap”方法將指示Eloquent對每個模型使用自定義名稱,而不是類名:

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>

我們可以在AppServiceProvider的boot函數中註冊morphMap,或者創建一個單獨的服務提供者。為了使新的更改生效,我們必須運行composer dump-autoload命令。因此,現在我們可以添加這個新的點贊記錄:

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

它的行為方式與之前的示例完全相同。

結論

即使您可能從未遇到過需要使用多態關係的情況,但那一天最終可能會到來。使用Laravel的好處是,處理這種情況非常容易,無需進行任何模型關聯技巧即可使事情正常工作。 Laravel甚至支持多對多多態關係。您可以在此處閱讀更多相關信息。

我希望您現在已經了解了多態關係以及可能需要這些類型關係的情況。另一個關於多態關係的稍微高級一點的例子在這裡。如果您覺得這有幫助,請與您的朋友分享,不要忘記點擊點贊按鈕。請隨時在下面的評論部分留下您的想法!

關於Eloquent的多態關係的常見問題解答

使用Laravel中的多態關係有哪些好處?

Laravel中的多態關係提供了一種靈活且有效的方式來處理不同模型之間的相關數據。它們允許一個模型在一個關聯上屬於多個其他類型的模型。這意味著您可以擁有所有相關數據的單個唯一標識符列表,而不管它們的類型如何。這可以極大地簡化您的數據庫結構並使您的代碼更易於維護。它還允許更動態和靈活的數據關係,這在復雜的應用程序中特別有用。

如何在Laravel中設置多態關係?

在Laravel中設置多態關係涉及在Eloquent模型中定義關係。首先,您需要在將接收多態關係的模型上定義關係。這是使用morphTo方法完成的。然後,在將與其他模型關聯的模型上,根據關係是一對多還是一對一,使用morphManymorphOne方法。

你能提供一個Laravel中多態關係的例子嗎?

當然,讓我們考慮一個博客平台,其中帖子和用戶都可以有評論。在這種情況下,Comment模型將與Post和User模型具有多態關係。以下是如何定義此關係:

<code>albums
    id - integer
    name - string

songs
    id - integer
    title - string
    album_id - integer

upvotes
    id - integer
    upvoteable_id - integer
    upvoteable_type - string
</code>

如何使用多態關係檢索相關記錄?

您可以像使用任何其他Eloquent關係一樣檢索多態關係中的相關記錄。例如,如果您想檢索帖子的所有評論,您可以這樣做:

<code>php artisan make:model Album -m
php artisan make:model Song -m
php artisan make:model Upvote -m
</code>

如何使用多態關係保存相關記錄?

保存多態關係中的相關記錄也類似於其他Eloquent關係。您可以使用associate方法關聯模型,然後保存模型。這是一個例子:

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

多態關係的一些常見用例是什麼?

在模型可以屬於多個其他類型模型的情況下,多態關係特別有用。一些常見的用例包括可以屬於帖子和用戶的評論、可以應用於多種類型內容的標籤以及可以附加到各種類型的實體的圖像或文件。

使用多態關係有哪些限製或缺點?

雖然多態關係提供了很大的靈活性,但它們也可能比標準的Eloquent關係更複雜,更難以設置和管理。它們也不支持標準關係的所有功能,例如渴望加載約束。

如何刪除多態關係中的相關記錄?

您可以使用關係上的delete方法刪除多態關係中的相關記錄。例如,要刪除帖子的所有評論,您可以這樣做:

public function up()
{
    Schema::create('songs', function (Blueprint $table) {
        $table->increments('id');
        $table->string('title');
        $table->integer('album_id')->unsigned()->index();
        $table->timestamps();

        $table->foreign('album_id')->references('id')->on('albums')->onDelete('cascade');
    });
}

我可以將多態關係與多對多關係一起使用嗎?

是的,Laravel通過morphToManymorphedByMany方法支持多對多多態關係。這允許一個模型在多對多的基礎上屬於多個模型。

如何在數據庫遷移中處理多態關係?

在數據庫遷移中,您通常會向將接收多態關係的表中添加兩列:一列用於相關模型ID,另一列用於相關模型類型。 Laravel提供了一個方便的morphs方法來添加這些列:

public function up()
{
    Schema::create('upvotes', function (Blueprint $table) {
        $table->increments('id');
        $table->morphs('upvoteable'); // 添加无符号整数 upvoteable_id 和字符串 upvoteable_type
        $table->timestamps();
    });
}

這會向表中添加commentable_idcommentable_type列。

以上是重新引入雄辯的多態關係的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
絕對會話超時有什麼區別?絕對會話超時有什麼區別?May 03, 2025 am 12:21 AM

絕對會話超時從會話創建時開始計時,閒置會話超時則從用戶無操作時開始計時。絕對會話超時適用於需要嚴格控制會話生命週期的場景,如金融應用;閒置會話超時適合希望用戶長時間保持會話活躍的應用,如社交媒體。

如果會話在服務器上不起作用,您將採取什麼步驟?如果會話在服務器上不起作用,您將採取什麼步驟?May 03, 2025 am 12:19 AM

服務器會話失效可以通過以下步驟解決:1.檢查服務器配置,確保會話設置正確。 2.驗證客戶端cookies,確認瀏覽器支持並正確發送。 3.檢查會話存儲服務,如Redis,確保其正常運行。 4.審查應用代碼,確保會話邏輯正確。通過這些步驟,可以有效診斷和修復會話問題,提升用戶體驗。

session_start()函數的意義是什麼?session_start()函數的意義是什麼?May 03, 2025 am 12:18 AM

session_start()iscucialinphpformanagingusersessions.1)ItInitiateSanewsessionifnoneexists,2)resumesanexistingsessions,and3)setsasesessionCookieforContinuityActinuityAccontinuityAcconActInityAcconActInityAcconAccRequests,EnablingApplicationsApplicationsLikeUseAppericationLikeUseAthenticationalticationaltication and PersersonalizedContentent。

為會話cookie設置httponly標誌的重要性是什麼?為會話cookie設置httponly標誌的重要性是什麼?May 03, 2025 am 12:10 AM

設置httponly標誌對會話cookie至關重要,因為它能有效防止XSS攻擊,保護用戶會話信息。具體來說,1)httponly標誌阻止JavaScript訪問cookie,2)在PHP和Flask中可以通過setcookie和make_response設置該標誌,3)儘管不能防範所有攻擊,但應作為整體安全策略的一部分。

PHP會議在網絡開發中解決了什麼問題?PHP會議在網絡開發中解決了什麼問題?May 03, 2025 am 12:02 AM

phpsessions solvathepromblymaintainingStateAcrossMultipleHttpRequestsbyStoringDataTaNthEserVerAndAssociatingItwithaIniquesestionId.1)他們儲存了AtoredAtaserver side,通常是Infilesordatabases,InseasessessionIdStoreDistordStoredStoredStoredStoredStoredStoredStoreDoreToreTeReTrestaa.2)

可以在PHP會話中存儲哪些數據?可以在PHP會話中存儲哪些數據?May 02, 2025 am 12:17 AM

phpsessionscanStorestrings,數字,數組和原始物。

您如何開始PHP會話?您如何開始PHP會話?May 02, 2025 am 12:16 AM

tostartaphpsession,usesesses_start()attheScript'Sbeginning.1)placeitbeforeanyOutputtosetThesessionCookie.2)useSessionsforuserDatalikeloginstatusorshoppingcarts.3)regenerateSessiveIdStopreventFentfixationAttacks.s.4)考慮使用AttActAcks.s.s.4)

什麼是會話再生,如何提高安全性?什麼是會話再生,如何提高安全性?May 02, 2025 am 12:15 AM

會話再生是指在用戶進行敏感操作時生成新會話ID並使舊ID失效,以防會話固定攻擊。實現步驟包括:1.檢測敏感操作,2.生成新會話ID,3.銷毀舊會話ID,4.更新用戶端會話信息。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

將Eclipse與SAP NetWeaver應用伺服器整合。