{"id":271,"date":"2025-08-27T18:25:40","date_gmt":"2025-08-27T18:25:40","guid":{"rendered":"https:\/\/1v0.net\/blog\/?p=271"},"modified":"2025-08-27T18:25:42","modified_gmt":"2025-08-27T18:25:42","slug":"laravel-eloquent-relationships-explained-with-examples","status":"publish","type":"post","link":"https:\/\/1v0.net\/blog\/laravel-eloquent-relationships-explained-with-examples\/","title":{"rendered":"Laravel Eloquent Relationships Explained with Examples"},"content":{"rendered":"\n<p>One of the most powerful features of <strong>Laravel 12<\/strong> is its <strong>Eloquent ORM<\/strong>. With Eloquent, you don\u2019t have to write complex SQL joins to connect your data models. Instead, you define <strong>relationships<\/strong> between models, and Laravel makes querying related data simple and expressive.<\/p>\n\n\n\n<p>In this guide, we\u2019ll cover the five major Eloquent relationships \u2014 <strong>one-to-one<\/strong>, <strong>one-to-many<\/strong>, <strong>many-to-many<\/strong>, <strong>has-many-through<\/strong>, and <strong>polymorphic<\/strong> \u2014 with full examples including migrations, model methods, queries, and Blade UI snippets. After each code block, you\u2019ll find a clear explanation so beginners won\u2019t get lost.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>1 &#8211; One to One Relationship<\/strong><\/h2>\n\n\n\n<p>A <strong>one-to-one<\/strong> relationship means one record in a table is related to exactly one record in another table. Example: every <code>User<\/code> has exactly one <code>Profile<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Migration: create_profiles_table.php<\/span>\nSchema::create(<span class=\"hljs-string\">'profiles'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n    $table-&gt;id();\n    $table-&gt;foreignId(<span class=\"hljs-string\">'user_id'<\/span>)-&gt;constrained()-&gt;onDelete(<span class=\"hljs-string\">'cascade'<\/span>);\n    $table-&gt;string(<span class=\"hljs-string\">'bio'<\/span>)-&gt;nullable();\n    $table-&gt;timestamps();\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This migration creates a <code>profiles<\/code> table with a <code>user_id<\/code> foreign key. <code>constrained()<\/code> sets the reference to <code>users.id<\/code>. <code>onDelete('cascade')<\/code> removes the profile when its user is deleted to keep data consistent.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Models\/User.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">profile<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;hasOne(Profile::class);\n}\n\n<span class=\"hljs-comment\">\/\/ app\/Models\/Profile.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">user<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;belongsTo(User::class);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>hasOne<\/code> defines the \u201cowner\u201d side (User \u2192 Profile). <code>belongsTo<\/code> defines the inverse (Profile \u2192 User). Eloquent infers the foreign key <code>user_id<\/code> from the model names.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Query + Blade<\/span>\n$user = User::with(<span class=\"hljs-string\">'profile'<\/span>)-&gt;find(<span class=\"hljs-number\">1<\/span>);\n$bio = optional($user-&gt;profile)-&gt;bio;\n\n<span class=\"hljs-comment\">\/\/ Blade<\/span>\n&lt;p&gt;Bio: {{ optional($user-&gt;profile)-&gt;bio }}&lt;\/p&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>with('profile')<\/code> eager-loads the related profile to avoid N+1 queries. <code>optional()<\/code> prevents errors if a user has no profile yet.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>2 &#8211; One to Many Relationship<\/strong><\/h2>\n\n\n\n<p>A <strong>one-to-many<\/strong> relationship is when one record can have multiple related records. Example: a <code>Post<\/code> has many <code>Comment<\/code> entries.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Migration: create_comments_table.php<\/span>\nSchema::create(<span class=\"hljs-string\">'comments'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n    $table-&gt;id();\n    $table-&gt;foreignId(<span class=\"hljs-string\">'post_id'<\/span>)-&gt;constrained()-&gt;onDelete(<span class=\"hljs-string\">'cascade'<\/span>);\n    $table-&gt;text(<span class=\"hljs-string\">'body'<\/span>);\n    $table-&gt;timestamps();\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Each comment points to its post using <code>post_id<\/code>. When a post is deleted, its comments are cleaned up automatically.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Models\/Post.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">comments<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;hasMany(Comment::class);\n}\n\n<span class=\"hljs-comment\">\/\/ app\/Models\/Comment.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">post<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;belongsTo(Post::class);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>hasMany<\/code> indicates a parent with multiple children. <code>belongsTo<\/code> defines the child pointing back to the parent. Eloquent assumes <code>post_id<\/code> as the foreign key.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Query + Blade<\/span>\n$post = Post::with(<span class=\"hljs-string\">'comments'<\/span>)-&gt;find(<span class=\"hljs-number\">1<\/span>);\n\n@<span class=\"hljs-keyword\">foreach<\/span>($post-&gt;comments <span class=\"hljs-keyword\">as<\/span> $comment)\n  &lt;p&gt;{{ $comment-&gt;body }}&lt;\/p&gt;\n@<span class=\"hljs-keyword\">endforeach<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We eager-load comments to avoid a query per comment. The Blade loop renders all related comments efficiently.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>3 &#8211; Many to Many Relationship<\/strong><\/h2>\n\n\n\n<p>A <strong>many-to-many<\/strong> relationship allows multiple records on both sides to be related. Classic example: <code>Post<\/code> \u2194 <code>Tag<\/code>. A post can have many tags, and a tag can belong to many posts, typically using a pivot table <code>post_tag<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Migration: create_tags_and_post_tag_tables.php<\/span>\nSchema::create(<span class=\"hljs-string\">'tags'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n    $table-&gt;id();\n    $table-&gt;string(<span class=\"hljs-string\">'name'<\/span>)-&gt;unique();\n    $table-&gt;timestamps();\n});\n\nSchema::create(<span class=\"hljs-string\">'post_tag'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n    $table-&gt;id();\n    $table-&gt;foreignId(<span class=\"hljs-string\">'post_id'<\/span>)-&gt;constrained()-&gt;onDelete(<span class=\"hljs-string\">'cascade'<\/span>);\n    $table-&gt;foreignId(<span class=\"hljs-string\">'tag_id'<\/span>)-&gt;constrained()-&gt;onDelete(<span class=\"hljs-string\">'cascade'<\/span>);\n    $table-&gt;timestamps();\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>We create the <code>tags<\/code> table and a pivot table <code>post_tag<\/code> that references both <code>posts<\/code> and <code>tags<\/code>. The pivot holds the relationships.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Models\/Post.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">tags<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;belongsToMany(Tag::class);\n}\n\n<span class=\"hljs-comment\">\/\/ app\/Models\/Tag.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">posts<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;belongsToMany(Post::class);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>belongsToMany<\/code> tells Eloquent to use a pivot table. By convention it expects <code>post_tag<\/code>. If you use a different name, pass it as the second argument.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">\/\/ Attaching \/ syncing tags\n$post = Post::find(1);\n$post-&gt;tags()-&gt;attach(&#91;1, 3]);       \/\/ add relationships\n$post-&gt;tags()-&gt;sync(&#91;2, 3, 5]);      \/\/ make the set exactly &#91;2,3,5]\n$post-&gt;tags()-&gt;detach(&#91;1]);          \/\/ remove relationships\n\n\/\/ Query + Blade\n$post = Post::with('tags')-&gt;find(1);\n\n@foreach($post-&gt;tags as $tag)\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"badge bg-secondary\"<\/span>&gt;<\/span>{{ $tag-&gt;name }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n@endforeach<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>attach<\/code> adds new pivot rows; <code>detach<\/code> removes them; <code>sync<\/code> replaces the entire set. Eager-loading keeps queries minimal.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>4 &#8211; Has Many Through<\/strong><\/h2>\n\n\n\n<p><strong>Has-many-through<\/strong> lets you access a distant relationship through an intermediate model. Example: a <code>Country<\/code> has many <code>Posts<\/code> <em>through<\/em> <code>User<\/code> (Country \u2192 Users \u2192 Posts). You can fetch all posts for a country without manually joining users.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Example tables<\/span>\n<span class=\"hljs-comment\">\/\/ countries: id, name<\/span>\n<span class=\"hljs-comment\">\/\/ users: id, country_id, name, ...<\/span>\n<span class=\"hljs-comment\">\/\/ posts: id, user_id, title, ...<\/span>\n\n<span class=\"hljs-comment\">\/\/ app\/Models\/Country.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">posts<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;hasManyThrough(\n        Post::class,   <span class=\"hljs-comment\">\/\/ final model<\/span>\n        User::class,   <span class=\"hljs-comment\">\/\/ through \/ intermediate model<\/span>\n        <span class=\"hljs-string\">'country_id'<\/span>,  <span class=\"hljs-comment\">\/\/ Foreign key on users table...<\/span>\n        <span class=\"hljs-string\">'user_id'<\/span>,     <span class=\"hljs-comment\">\/\/ Foreign key on posts table...<\/span>\n        <span class=\"hljs-string\">'id'<\/span>,          <span class=\"hljs-comment\">\/\/ Local key on countries table...<\/span>\n        <span class=\"hljs-string\">'id'<\/span>           <span class=\"hljs-comment\">\/\/ Local key on users table...<\/span>\n    );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>hasManyThrough<\/code> signature is <code>(Final, Through, throughKey, finalKey, localKey, throughLocalKey)<\/code>. Here, a country\u2019s <code>id<\/code> matches users\u2019 <code>country_id<\/code>, and users\u2019 <code>id<\/code> matches posts\u2019 <code>user_id<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Query + Blade<\/span>\n$country = Country::with(<span class=\"hljs-string\">'posts'<\/span>)-&gt;find(<span class=\"hljs-number\">1<\/span>);\n\n&lt;h3&gt;Posts from {{ $country-&gt;name }}&lt;\/h3&gt;\n@<span class=\"hljs-keyword\">foreach<\/span>($country-&gt;posts <span class=\"hljs-keyword\">as<\/span> $post)\n  &lt;p&gt;{{ $post-&gt;title }} by {{ $post-&gt;user-&gt;name }}&lt;\/p&gt;\n@<span class=\"hljs-keyword\">endforeach<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>With one relationship method, you jump across the <code>users<\/code> table to get all posts for a country. This keeps your controllers simple.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\"><strong>5 &#8211; Polymorphic Relationships<\/strong><\/h2>\n\n\n\n<p><strong>Polymorphic<\/strong> relationships allow a model to belong to more than one type of model using a single association. Common use cases: a universal <code>Comment<\/code> or <code>Like<\/code> model that can attach to <code>Post<\/code>, <code>Video<\/code>, <code>Photo<\/code>, etc.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>5.1 &#8211; One-to-Many Polymorphic (comments on posts &amp; videos)<\/strong><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Migration: create_comments_table.php<\/span>\nSchema::create(<span class=\"hljs-string\">'comments'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n    $table-&gt;id();\n    $table-&gt;morphs(<span class=\"hljs-string\">'commentable'<\/span>); <span class=\"hljs-comment\">\/\/ creates commentable_id (bigint) &amp; commentable_type (string)<\/span>\n    $table-&gt;text(<span class=\"hljs-string\">'body'<\/span>);\n    $table-&gt;timestamps();\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>morphs('commentable')<\/code> creates two columns that together define the parent model (e.g., Post or Video) and the parent id. The same table can store comments for multiple models.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Models\/Comment.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">commentable<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;morphTo();\n}\n\n<span class=\"hljs-comment\">\/\/ app\/Models\/Post.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">comments<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;morphMany(Comment::class, <span class=\"hljs-string\">'commentable'<\/span>);\n}\n\n<span class=\"hljs-comment\">\/\/ app\/Models\/Video.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">comments<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;morphMany(Comment::class, <span class=\"hljs-string\">'commentable'<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><code>morphTo<\/code> is used on the child (<code>Comment<\/code>) to point to any parent. Each possible parent model (<code>Post<\/code>, <code>Video<\/code>) declares <code>morphMany<\/code> with the same \u201cmorph name\u201d (<code>commentable<\/code>).<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Usage + Blade<\/span>\n$post = Post::with(<span class=\"hljs-string\">'comments'<\/span>)-&gt;find(<span class=\"hljs-number\">1<\/span>);\n$video = Video::with(<span class=\"hljs-string\">'comments'<\/span>)-&gt;find(<span class=\"hljs-number\">5<\/span>);\n\n@<span class=\"hljs-keyword\">foreach<\/span>($post-&gt;comments <span class=\"hljs-keyword\">as<\/span> $c)\n  &lt;p&gt;Post comment: {{ $c-&gt;body }}&lt;\/p&gt;\n@<span class=\"hljs-keyword\">endforeach<\/span>\n\n@<span class=\"hljs-keyword\">foreach<\/span>($video-&gt;comments <span class=\"hljs-keyword\">as<\/span> $c)\n  &lt;p&gt;Video comment: {{ $c-&gt;body }}&lt;\/p&gt;\n@<span class=\"hljs-keyword\">endforeach<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Same <code>comments<\/code> table, two different parents. Eloquent keeps it consistent with the <code>commentable_type<\/code> and <code>commentable_id<\/code> columns.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>5.2 &#8211; Many-to-Many Polymorphic (tags for posts &amp; videos)<\/strong><\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Migration: create_tags_and_taggables.php<\/span>\nSchema::create(<span class=\"hljs-string\">'tags'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n    $table-&gt;id();\n    $table-&gt;string(<span class=\"hljs-string\">'name'<\/span>)-&gt;unique();\n    $table-&gt;timestamps();\n});\n\nSchema::create(<span class=\"hljs-string\">'taggables'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-params\">(Blueprint $table)<\/span> <\/span>{\n    $table-&gt;id();\n    $table-&gt;foreignId(<span class=\"hljs-string\">'tag_id'<\/span>)-&gt;constrained()-&gt;onDelete(<span class=\"hljs-string\">'cascade'<\/span>);\n    $table-&gt;morphs(<span class=\"hljs-string\">'taggable'<\/span>); <span class=\"hljs-comment\">\/\/ taggable_id + taggable_type<\/span>\n    $table-&gt;timestamps();\n});<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The <code>taggables<\/code> table connects a tag to any taggable model (post, video, etc.). This lets you reuse one tagging system application-wide.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ app\/Models\/Tag.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">posts<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;morphedByMany(Post::class, <span class=\"hljs-string\">'taggable'<\/span>);\n}\n\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">videos<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;morphedByMany(Video::class, <span class=\"hljs-string\">'taggable'<\/span>);\n}\n\n<span class=\"hljs-comment\">\/\/ app\/Models\/Post.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">tags<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;morphToMany(Tag::class, <span class=\"hljs-string\">'taggable'<\/span>);\n}\n\n<span class=\"hljs-comment\">\/\/ app\/Models\/Video.php<\/span>\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">tags<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">$this<\/span>-&gt;morphToMany(Tag::class, <span class=\"hljs-string\">'taggable'<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>On the \u201cthing being tagged\u201d (Post\/Video), use <code>morphToMany<\/code>. On the Tag side, use <code>morphedByMany<\/code> for each taggable type. Eloquent handles the morph columns automatically.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">\/\/ Usage + Blade\n$post = Post::with('tags')-&gt;find(1);\n$video = Video::with('tags')-&gt;find(1);\n\n@foreach($post-&gt;tags as $tag)\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"badge bg-info\"<\/span>&gt;<\/span>#{{ $tag-&gt;name }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n@endforeach\n\n@foreach($video-&gt;tags as $tag)\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"badge bg-warning\"<\/span>&gt;<\/span>#{{ $tag-&gt;name }}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>\n@endforeach<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>You can attach\/detach\/sync tags using the relationship just like a normal many-to-many, but now polymorphic across different models.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>You\u2019ve learned the essential Eloquent relationships in Laravel 12 with practical, copy-paste examples: <strong>one-to-one<\/strong> (User\u2013Profile), <strong>one-to-many<\/strong> (Post\u2013Comments), <strong>many-to-many<\/strong> (Post\u2013Tags), <strong>has-many-through<\/strong> (Country\u2013Posts through Users), and <strong>polymorphic<\/strong> (Comments\/Tags across multiple models). With these in your toolbox, you can model most real-world data cleanly and query it efficiently \u2014 while keeping your controllers and views simple.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n\n<h2 class=\"wp-block-heading\">What\u2019s Next<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/blog\/eager-loading-vs-lazy-loading-in-laravel-best-practices\">Eager Loading vs Lazy Loading in Laravel: Best Practices<\/a><\/li>\n<li><a href=\"\/blog\/how-to-use-laravel-query-scopes-for-cleaner-code\">How to Use Laravel Query Scopes for Cleaner Code<\/a><\/li>\n<li><a href=\"\/blog\/filtering-and-searching-with-laravel-eloquent-query-builder\">Filtering and Searching with Laravel Eloquent Query Builder<\/a><\/li>\n<\/ul>\n\n","protected":false},"excerpt":{"rendered":"<p>One of the most powerful features of Laravel 12 is its Eloquent ORM. With Eloquent, you don\u2019t have to write complex SQL joins to connect your data models. Instead, you define relationships between models, and Laravel makes querying related data simple and expressive. In this guide, we\u2019ll cover the five major Eloquent relationships \u2014 one-to-one, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":275,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[38,36,37],"class_list":["post-271","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-laravel","tag-database","tag-eloquent","tag-relationships"],"_links":{"self":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/271","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/comments?post=271"}],"version-history":[{"count":1,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/271\/revisions"}],"predecessor-version":[{"id":274,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/271\/revisions\/274"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media\/275"}],"wp:attachment":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media?parent=271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/categories?post=271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/tags?post=271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}