A comprehensive guide and implementation of polymorphic relationships in Laravel, demonstrating both one-to-many and many-to-many polymorphic relationships through a practical example.
more information at - https://medium.com/@murilolivorato/mastering-polymorphic-relationships-in-laravel-a-comprehensive-guide-ff3bc3ef2b64
This project demonstrates how to implement polymorphic relationships in Laravel using a blog-like application where:
- Posts and Videos can have Comments (one-to-many polymorphic)
- Posts and Videos can have Tags (many-to-many polymorphic)
- A single relationship structure can be reused across different models
- One-to-many polymorphic relationships (Comments)
- Many-to-many polymorphic relationships (Tags)
- RESTful API implementation
- Factory and Seeder setup
- Postman collections for API testing
- Comprehensive model relationships
- PHP 8.1 or higher
- Composer
- Laravel 10.x
- MySQL or another database system
- Postman (for API testing)
- Clone the repository:
git clone <your-repository-url>
cd polymorphic-example
- Install dependencies:
composer install
- Configure your environment:
cp .env.example .env
php artisan key:generate
- Run migrations and seed the database:
php artisan migrate
php artisan db:seed
posts
- Stores blog postsvideos
- Stores video contentcomments
- Stores comments (polymorphic)tags
- Stores tagstaggables
- Polymorphic pivot table for tags
-
One-to-Many Polymorphic (Comments)
- Posts can have many comments
- Videos can have many comments
- Comments belong to either posts or videos
-
Many-to-Many Polymorphic (Tags)
- Posts can have many tags
- Videos can have many tags
- Tags can belong to many posts and videos
Before you begin, ensure you have met the following requirements:
- PHP >= 8.0
- Composer
- Node.js and npm
- A web server (e.g., Apache, Nginx)
- A database server (e.g., MySQL, PostgreSQL)
-
Clone the repository:
git clone https://github.com/murilolivorato/laravel-polymorphs-project.git cd laravel-polymorphs
-
Install PHP dependencies using Composer:
composer install
-
Install JavaScript dependencies using npm:
npm install
-
Copy the
.env.example
file to.env
and configure your environment variables:cp .env.example .env
-
Generate an application key:
php artisan key:generate
-
Run database migrations:
php artisan migrate
-
Start the local development server:
php artisan serve
-
Access the application in your web browser at
http://localhost:8000
.
To run the tests, use the following command:
php artisan test
{
"info": {
"name": "PostController API",
"_postman_id": "12345-67890-abcdef",
"description": "Collection for PostController API endpoints",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Get All Posts",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/posts",
"host": ["{{base_url}}"],
"path": ["api", "posts"]
}
}
},
{
"name": "Create Post",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"title\": \"Sample Post\",\n \"body\": \"This is a sample post body.\"\n}"
},
"url": {
"raw": "{{base_url}}/api/posts",
"host": ["{{base_url}}"],
"path": ["api", "posts"]
}
}
},
{
"name": "Get Post by ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/posts/:id",
"host": ["{{base_url}}"],
"path": ["api", "posts", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
},
{
"name": "Update Post",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"title\": \"Updated Post Title\",\n \"body\": \"Updated post body content.\"\n}"
},
"url": {
"raw": "{{base_url}}/api/posts/:id",
"host": ["{{base_url}}"],
"path": ["api", "posts", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
},
{
"name": "Delete Post",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}/api/posts/:id",
"host": ["{{base_url}}"],
"path": ["api", "posts", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
}
]
}
{
"info": {
"name": "CommentController API",
"_postman_id": "12345-67890-abcdef",
"description": "Collection for CommentController API endpoints",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Get All Comments",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/comments",
"host": ["{{base_url}}"],
"path": ["api", "comments"]
}
}
},
{
"name": "Create Comment",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"body\": \"This is a sample comment body.\"\n}"
},
"url": {
"raw": "{{base_url}}/api/comments",
"host": ["{{base_url}}"],
"path": ["api", "comments"]
}
}
},
{
"name": "Get Comment by ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/comments/:id",
"host": ["{{base_url}}"],
"path": ["api", "comments", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
},
{
"name": "Update Comment",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"body\": \"Updated comment body content.\"\n}"
},
"url": {
"raw": "{{base_url}}/api/comments/:id",
"host": ["{{base_url}}"],
"path": ["api", "comments", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
},
{
"name": "Delete Comment",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}/api/comments/:id",
"host": ["{{base_url}}"],
"path": ["api", "comments", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
}
]
}
{
"info": {
"name": "TagController API",
"_postman_id": "12345-67890-abcdef",
"description": "Collection for TagController API endpoints",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Get All Tags",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/tags",
"host": ["{{base_url}}"],
"path": ["api", "tags"]
}
}
},
{
"name": "Create Tag",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Sample Tag\"\n}"
},
"url": {
"raw": "{{base_url}}/api/tags",
"host": ["{{base_url}}"],
"path": ["api", "tags"]
}
}
},
{
"name": "Get Tag by ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/tags/:id",
"host": ["{{base_url}}"],
"path": ["api", "tags", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
},
{
"name": "Update Tag",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"name\": \"Updated Tag Name\"\n}"
},
"url": {
"raw": "{{base_url}}/api/tags/:id",
"host": ["{{base_url}}"],
"path": ["api", "tags", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
},
{
"name": "Delete Tag",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}/api/tags/:id",
"host": ["{{base_url}}"],
"path": ["api", "tags", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
}
]
}
{
"info": {
"name": "VideoController API",
"_postman_id": "12345-67890-abcdef",
"description": "Collection for VideoController API endpoints",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "Get All Videos",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/videos",
"host": ["{{base_url}}"],
"path": ["api", "videos"]
}
}
},
{
"name": "Create Video",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"title\": \"Sample Video\",\n \"description\": \"This is a sample video description.\"\n}"
},
"url": {
"raw": "{{base_url}}/api/videos",
"host": ["{{base_url}}"],
"path": ["api", "videos"]
}
}
},
{
"name": "Get Video by ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/api/videos/:id",
"host": ["{{base_url}}"],
"path": ["api", "videos", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
},
{
"name": "Update Video",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"title\": \"Updated Video Title\",\n \"description\": \"Updated video description.\"\n}"
},
"url": {
"raw": "{{base_url}}/api/videos/:id",
"host": ["{{base_url}}"],
"path": ["api", "videos", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
},
{
"name": "Delete Video",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}/api/videos/:id",
"host": ["{{base_url}}"],
"path": ["api", "videos", ":id"],
"variable": [
{
"key": "id",
"value": "1"
}
]
}
}
}
]
}
For questions, suggestions, or collaboration:
- Author: Murilo Livorato
- GitHub: murilolivorato
- linkedIn: https://www.linkedin.com/in/murilo-livorato-80985a4a/