laravel Design patterns, solid principles and code example and polymorphic relation
Design Patterns:
1.MVC (Model-View-Controller): Laravel follows the MVC pattern, which separates the application into three main components. Models represent the data and business logic, Views are responsible for rendering the UI, and Controllers handle the interaction between the Model and View.
2.Repository Pattern: The Repository pattern abstracts the data persistence layer from the application logic. It provides a consistent API to access and manipulate data, regardless of the underlying data source. This pattern helps with decoupling and improves testability and maintainability.
3.Factory Pattern: Laravel uses the Factory pattern to create objects or instances. It centralizes the object creation logic, making it easier to manage dependencies and provide a consistent way to create complex objects.
SOLID Principles:
1.Single Responsibility Principle (SRP): Each class or module should have a single responsibility and should only be responsible for one thing.
2.Open/Closed Principle (OCP): Classes should be open for extension but closed for modification. This means that you should be able to add new functionality without modifying existing code.
3.Liskov Substitution Principle (LSP): Subtypes must be substitutable for their base types without affecting the correctness of the program. In other words, if you have a class, you should be able to use any of its derived classes without breaking the code.
4.Interface Segregation Principle (ISP): Clients should not be forced to depend on interfaces they do not use. It's better to have smaller, focused interfaces rather than large, monolithic ones.
5.Dependency Inversion Principle (DIP): High-level modules should not depend on low-level modules; both should depend on abstractions. Abstractions should not depend on details; details should depend on abstractions. This principle promotes loose coupling and improves flexibility and maintainability.
Code Example: Let's consider an example where we have a User model that needs to interact with a UserRepository using the repository pattern. Here's how it could be implemented with SOLID principles:
// UserRepository.php interface UserRepositoryInterface { public function getById($id); public function save(User $user); } class UserRepository implements UserRepositoryInterface { public function getById($id) { // Fetch user from the database } public function save(User $user) { // Save the user to the database } } // UserService.php class UserService { private $userRepository; public function __construct(UserRepositoryInterface $userRepository) { $this->userRepository = $userRepository; } public function getUser($id) { return $this->userRepository->getById($id); } public function saveUser(User $user) { // Perform validation or additional logic $this->userRepository->save($user); } } // UserController.php class UserController { private $userService; public function __construct(UserService $userService) { $this->userService = $userService; } public function show($id) { $user = $this->userService->getUser($id); // Render user view } public function store(Request $request) { // Validate request $user = new User($request->all()); $this->userService->saveUser($user); // Redirect or return response } }
In the code example above, the UserRepository class implements the UserRepositoryInterface, adhering to the interface segregation principle.
laravel smart code example:-
namespace App\Http\Controllers; use App\Models\Post; use App\Http\Requests\CreatePostRequest; use App\Services\PostService; use Illuminate\Http\Request; class PostController extends Controller { private $postService; public function __construct(PostService $postService) { $this->postService = $postService; } public function index() { $posts = $this->postService->getAllPosts(); return view('posts.index', compact('posts')); } public function create() { return view('posts.create'); } public function store(CreatePostRequest $request) { $validatedData = $request->validated(); $this->postService->createPost($validatedData); return redirect()->route('posts.index')->with('success', 'Post created successfully.'); } public function show(Post $post) { return view('posts.show', compact('post')); } public function edit(Post $post) { return view('posts.edit', compact('post')); } public function update(Request $request, Post $post) { $this->postService->updatePost($post, $request->all()); return redirect()->route('posts.index')->with('success', 'Post updated successfully.'); } public function destroy(Post $post) { $this->postService->deletePost($post); return redirect()->route('posts.index')->with('success', 'Post deleted successfully.'); } }
In this example, the code demonstrates the following smart coding practices:
Dependency Injection: The
PostControllerclass has a constructor that accepts an instance of thePostServiceclass. This promotes loose coupling and allows for easier testing and swapping of implementations.Type Hinting: Type hinting is used for the method parameters. For example, the
storemethod accepts aCreatePostRequestobject, and theupdatemethod accepts aRequestobject. This enhances code clarity and enables Laravel's automatic dependency injection and validation features.Validation: The
storemethod validates the incoming request using theCreatePostRequestclass. This promotes data integrity and ensures that the request data meets the required validation rules.Service Layer: The
PostControllerinteracts with thePostServiceclass to perform operations related to posts. This separation of concerns adheres to the Single Responsibility Principle and keeps the controller lean by delegating business logic to the service layer.Routing and Views: The controller methods are associated with specific routes and views, following Laravel's conventions. For example, the
indexmethod returns theposts.indexview, which will render a list of posts.
In this continuation, we have a PostService class responsible for performing CRUD operations on posts. The service layer encapsulates the business logic and abstracts away the database operations, providing a more organized and maintainable approach.
Here's a breakdown of the methods in the PostService class:
getAllPosts: Retrieves all posts from the database and returns them in descending order based on the creation date.
createPost: Creates a new post in the database using the provided data. The
$dataparameter is an array containing the necessary attributes for the post.updatePost: Updates an existing post with the given data. The
$postparameter is thePostmodel instance representing the post to be updated.deletePost: Deletes a post from the database. The
$postparameter is thePostmodel instance representing the post to be deleted.
By encapsulating the database operations within the PostService class, we can easily reuse the logic across multiple controllers or other parts of the application. This promotes code reusability and enhances maintainability.
namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class CreatePostRequest extends FormRequest { public function authorize() { return true; } public function rules() { return [ 'title' => 'required|string|max:255', 'content' => 'required|string', ]; } }
In this continuation, we have a CreatePostRequest class, which extends Laravel's FormRequest class. This class handles the validation rules for creating a post.
Let's take a closer look at the methods within the CreatePostRequest class:
authorize: The
authorizemethod determines whether the authenticated user is authorized to make the request. In this example, we're allowing any user to create a post by returningtrue. You can add custom authorization logic based on your application's requirements.rules: The
rulesmethod defines the validation rules for the incoming request. In this example, thetitlefield is required, must be a string, and have a maximum length of 255 characters. Thecontentfield is also required and must be a string.
By utilizing form requests in Laravel, you can centralize the validation logic for specific request types. This promotes reusability and simplifies the controller's responsibility, as the validated data is readily available in the controller method.
laravel polymorphic one to one, one to many, many to many relationship explain and code example:-
- One-to-One Polymorphic Relationship:-
In a one-to-one polymorphic relationship, a model can belong to only one of several models. Here's an example:
class Image extends Model { public function imageable() { return $this->morphTo(); } } class User extends Model { public function image() { return $this->morphOne(Image::class, 'imageable'); } } class Post extends Model { public function image() { return $this->morphOne(Image::class, 'imageable'); } }
In this example, both the User and Post models have a one-to-one polymorphic relationship with the Image model through the imageable relationship. The Image model can belong to either a User or a Post model.
- One-to-Many Polymorphic Relationship:
In a one-to-many polymorphic relationship, a model can have multiple associations with several models. Here's an example:
class Comment extends Model { public function commentable() { return $this->morphTo(); } } class Post extends Model { public function comments() { return $this->morphMany(Comment::class, 'commentable'); } } class Video extends Model { public function comments() { return $this->morphMany(Comment::class, 'commentable'); } }
In this example, both the Post and Video models have a one-to-many polymorphic relationship with the Comment model through the commentable relationship. The Comment model can belong to either a Post or a Video model.
- Many-to-Many Polymorphic Relationship:
In a many-to-many polymorphic relationship, a model can have multiple associations with several models, and those models can have associations with other models as well. Here's an example:
class Tag extends Model { public function posts() { return $this->morphedByMany(Post::class, 'taggable'); } public function videos() { return $this->morphedByMany(Video::class, 'taggable'); } } class Post extends Model { public function tags() { return $this->morphToMany(Tag::class, 'taggable'); } } class Video extends Model { public function tags() { return $this->morphToMany(Tag::class, 'taggable'); } }
In this example, the Post and Video models have a many-to-many polymorphic relationship with the Tag model through the taggable relationship. The Tag model can be associated with multiple Post or Video models, and vice versa.
- One-to-One Polymorphic Relationship Migration:
Create a migration file to add the images table:
public function up() { Schema::create('images', function (Blueprint $table) { $table->id(); $table->string('url'); $table->morphs('imageable'); $table->timestamps(); }); }
- One-to-Many Polymorphic Relationship Migration:
Create a migration file to add the comments table:
public function up() { Schema::create('comments', function (Blueprint $table) { $table->id(); $table->text('content'); $table->morphs('commentable'); $table->timestamps(); }); }
- Many-to-Many Polymorphic Relationship Migration:
Create a migration file to create the pivot table for the tags and related models:
public function up() { Schema::create('taggables', function (Blueprint $table) { $table->unsignedBigInteger('tag_id'); $table->unsignedBigInteger('taggable_id'); $table->string('taggable_type'); $table->timestamps(); $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); }); }
Make sure to run php artisan migrate command after creating these migration files to apply the changes to your database.
No comments