Original link: learnku.com/laravel/t/4… For discussion, head to the professional Laravel developer forum: learnku.com/Laravel
Design patterns are important to every developer. It addresses a very common problem in every project you build.
Decorator pattern definition:
It helps you add additional behavior to one object without affecting other objects in the same class.
Wikipedia:
The decorator pattern is a design pattern that allows behavior to be dynamically added to a single object without affecting the behavior of other objects in the same class
The problem
Suppose we have a Post model
class Post extends Model
{
public function scopePublished($query) {
return $query->where('published_at'.'< ='.'NOW()'); }}Copy the code
In our PostsController, we have the following index method
class PostsController extends Controller
{
public function index() {
$posts = Post::published()->get();
return $posts; }}Copy the code
To cache the posts and avoid querying the database every time we need to list the posts, we can do the following
class PostsController extends Controller
{
public function index() {
$minutes = 1440; # 1 day
$posts = Cache::remember('posts'.$minutes.function () {
return Post::published()->get();
});
return $posts; }}Copy the code
Now, we cache the posts for 1 day. But looking at the code, the controller knows too much. It knows how many days we’ve been caching, and it caches the object itself.
Again, suppose you are implementing the same functionality for HomePageController’s Tag, Category, and Archives. Too much code to read and maintain.
The warehouse model
In most cases, warehouse mode is connected to decorator mode.
First of all, let us use warehouse mode separation post way, created with the following contents of app/Repositories/Posts/PostsRepositoryInterface. PHP
namespace App\Repositories\Posts;
interface PostsRepositoryInterface
{
public function get();
public function find(int $id);
}
Copy the code
Create a PostsRepository with the following contents in the same directory
namespace App\Repositories\Posts;
use App\Post;
class PostsRepository implements PostsRepositoryInterface
{
protected $model;
public function __construct(Post $model) {
$this->model = $model;
}
public function get() {
return $this->model->published()->get();
}
public function find(int $id) {
return $this->model->published()->find($id); }}Copy the code
Go back to PostsController and apply the changes to
namespace App\Http\Controllers;
use App\Repositories\Posts\PostsRepositoryInterface;
use Illuminate\Http\Request;
class PostsController extends Controller
{
public function index(PostsRepositoryInterface $postsRepo) {
return $postsRepo->get(); }}Copy the code
The controller becomes healthy and knows enough detail to get the job done.
Here, we rely on Laravel’s IOC to inject concrete objects into the Posts interface to get our Posts
All we need to do is tell Laravel’s IOC which class to create when using the interface.
In your app/will/AppServiceProvider. PHP add binding method
namespace App\Providers;
use App\Repositories\Posts\PostsRepositoryInterface;
use App\Repositories\Posts\PostsRepository;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PostsRepositoryInterface::class,PostsRepository::class); }}Copy the code
Now whenever we inject PostsRepositoryInterface Laravel creates an instance of PostsRepository and returns it.
Caching is implemented through decorators
As we said at the outset, the decorator pattern allows behavior to be added to a single object without affecting other objects in the same class.
Here the cache is the behavior and the object/class is PostsRepository.
Let us in the app/Repositories/Posts/PostsCacheRepository. PHP PostsCacheRepository create has the following content
namespace App\Repositories\Posts;
use App\Post;
use Illuminate\Cache\CacheManager;
class PostsCacheRepository implements PostsRepositoryInterface
{
protected $repo;
protected $cache;
const TTL = 1440; # 1 day
public function __construct(CacheManager $cache, PostsRepository $repo) {
$this->repo = $repo;
$this->cache = $cache;
}
public function get() {
return $this->cache->remember('posts', self::TTL, function () {
return $this->repo->get();
});
}
public function find(int $id) {
return $this->cache->remember('posts.'.$id, self::TTL, function () {
return $this->repo->find($id); }); }}Copy the code
In this class, we accept a Caching object and a PostsRepository object, and then use the class (decorator) to add the Caching behavior to the PostsReposiory instance.
We could use the same example to send an HTTP request to some service and then return to the model in case of failure. I’m sure you’ll benefit from this pattern and how easy it is to add behavior.
The last thing is to modify the AppServiceProvider interface binding to create a PostsCacheRepository instance instead of a PostsRepository
namespace App\Providers;
use App\Repositories\Posts\PostsRepositoryInterface;
use App\Repositories\Posts\PostsCacheRepository;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(PostsRepositoryInterface::class,PostsCacheRepository::class); }}Copy the code
Now examine the file again, and you’ll see that it’s very easy to read and maintain. Again, it is testable if you decide to remove the cache layer at some point. You just need to change the binding in AppServiceProvider. No additional changes required.
conclusion
- We learned how to cache the model using the decorator pattern
- We showed how the repository pattern connects to the decorator pattern
- How can attachment injection and Laravel IOC make our lives easier
- Laravel components are powerful
Hope you enjoyed reading this article. It shows you powerful design patterns, and how to make your projects easy to maintain and manage
Original link: learnku.com/laravel/t/4… For discussion, head to the professional Laravel developer forum: learnku.com/Larav