首页 >后端开发 >php教程 >您的 Laravel 应用程序与存储库没有任何意义

您的 Laravel 应用程序与存储库没有任何意义

PHPz
PHPz原创
2024-08-02 09:42:23993浏览

Your Laravel application with Repository doesn

多年来,我看到许多开发人员在 Laravel 中使用存储库模式,试图将干净的架构概念应用于他们的应用程序,但经常误解使用像 Laravel 这样的框架的一般概念.

在我开始并必须避开一些我知道你们可能会扔给我的石头之前,让我澄清一下:这是我作为一名软件工程师的观点,他曾使用过多种语言、框架,从头开始构建软件,并且维护旧的遗留代码库。我的话不是最终的,并且一如既往,我相信任何软件工程问题最可接受的答案是:“这取决于您愿意为了解决问题而做出权衡。”

那么,话不多说,让我们进入正题吧。

什么是清洁架构?

清洁架构是一种软件设计理念,旨在创建易于维护、测试和理解的系统。它强调关注点的分离以及系统不同部分之间边界的创建,以确保一个部分的更改不会对其他部分产生不利影响。这种架构由 Robert C. Martin(Bob 叔叔)推广,通常用于指导代码组织,以适应业务规则或技术要求的变化。

简而言之,Bob 的建议是,您的应用程序应该分为遵循关键原则的层,以允许您的业务逻辑与任何外部依赖项解耦,从而为它们提供移动性和单一职责上下文。但这不会是一篇干净的架构文章;我只是想让我们在这件事上达成共识。

Laravel 和清洁架构怎么样?

说到框架,我们谈论的是依赖关系的紧密耦合。您可能没有选择 Laravel 来使用 Doctrine;您可能选择使用 Eloquent。这同样适用于您可能找到的任何框架功能 - 您选择框架是为了开发速度和便利性。

所以,我的问题是:为什么要在你选择简单的东西上添加额外的复杂层?

等等,别因为我这么说而恨我。您仍然可以在 Laravel 中适应甚至使用干净的架构,但任何架构决策中最重要的方面是清楚地了解您想要实现的目标以及这些选择的优缺点。

这是一个艰难的决定,您可以在实施过程中改变主意。软件不应该是一成不变的,对吧?我有一篇关于软件质量的整篇文章,我在其中举起了这个旗帜。

无论如何,回到 Laravel 和干净的架构。以我的拙见,最烦人的方法之一是将存储库模式与 Eloquent 结合使用,这就是我写这篇文章的动机。

存储库模式

存储库模式是一种在域和数据映射层之间进行中介的设计模式,充当域对象的内存集合。它的目的是解耦领域和数据映射层。

因此,存储库定义是一个域实体。为什么?因为它与域交互并定义基础设施如何与域交互,充当域和我们应用程序的基础设施层之间的契约。

Laravel 上的存储库模式

首先,让我向您展示我在 Laravel 应用程序中经常看到的存储库模式的一个糟糕实现,然后为您修复它:

// app/Repositories/UserRepositoryInterface.php
<?php

namespace App\Repositories;

interface UserRepositoryInterface
{
  // ...methods definitions
}
// app/Repositories/UserRepository.php
<?php

namespace App\Repositories;

class UserRepository implements UserRepositoryInterface
{
   // ...implementation
}

正如您在上面的代码中看到的,域和基础设施的“契约”不是在域内部定义的,而是在基础设施本身内部定义的。是的,App 命名空间是应用程序层的一部分,它包含所有非域的东西。

现在,让我们看看如何实现同样的事情:

// domain/Repositories/UserRepositoryInterface.php
<?php

namespace Domain\Repositories;

interface UserRepositoryInterface
{
  // ...methods definitions
}
// app/Repositories/UserRepository.php
<?php

namespace App\Repositories;

use Domain\Repositories\UserRepositoryInterface;

class UserRepository implements UserRepositoryInterface
{
   // ...implementation
}

请注意,现在我们有了适当的领域层和应用程序层。是不是很简单就可以得到呢?

Eloquent 的存储库模式

现在,让我们想一下。由于存储库接口现在是域的一部分,这意味着我们不能简单地将其他层的依赖项注入其中。这是一个不好的例子来解释它:

// app/Repositories/UserRepositoryInterface.php
<?php

namespace App\Repositories;

use App\Models\User;

interface UserRepositoryInterface
{
  public function find(int $id): User|null;
  // ...other methods
}

还不清楚吗?让我把它移到领域层:

// domain/Repositories/UserRepositoryInterface.php
<?php

namespace Domain\Repositories;

use App\Models\User;

interface UserRepositoryInterface
{
  public function find(int $id): User|null;
  // ...other methods
}

看到问题了吗?我们正在将作为基础设施层一部分的 Eloquent 模型注入到我们的领域中。这将我们的领域与 Eloquent 紧密耦合,这违背了存储库模式的目的。

But how do we solve it? Well, it is not as hard as you might think. You probably already heard about Entities, right? So, let’s fix it:

// domain/Repositories/UserRepositoryInterface.php
<?php

namespace Domain\Repositories;

use Domain\Entities\User;

interface UserRepositoryInterface
{
  public function find(int $id): User|null;
  // ...other methods
}
// domain/Entities/User.php
<?php

namespace Domain\Entities;

class User
{
  public function __construct(
    public int $id;
    public string $name;
    public string $email;
  ) {}
  // ...other properties and methods
}

Our domain layer is now clean from external dependencies, and if we want to move the whole domain to another framework, we can do it.

Now, how do we implement our Repository in our Laravel application? Let me show you:

// app/Repositories/EloquentUserRepository.php
<?php

namespace App\Repositories;

use Domain\Repositories\UserRepositoryInterface;
use Domain\Entities\User;
use App\Models\User as EloquentUser;

class EloquentUserRepository implements UserRepositoryInterface
{
    public function find(int $id): ?User {
        $eloquentUser = EloquentUser::find($id);
        return $eloquentUser ? $this->toDomain($eloquentUser): null;
    }

    private function toDomain(EloquentUser $eloquentUser): User
    {
        return new User(
          $eloquentUser->id, 
          $eloquentUser->name, 
          $eloquentUser->email
        );
    }
}

Now we have a proper implementation of the Repository pattern in Laravel using Eloquent. You can create any other Repository implementation, such as PDOUserRepository.php, DoctrineUserRepository.php, and many others without injecting any dependency into your Domain layer.

Do You Really Need to Use Repository?

Back to what I said in the subject of this article, I’ll complement that, in my humble opinion, using the Repository Pattern with Laravel is just overengineering, and you need a really good reason to do it.

You are adding an extra layer of complexity to your application that you may not need at all, or even worse, it will not guarantee that your business logic is actually isolated into the Domain layer.

What are you trying to achieve here? Think about it. You might end up missing out on many nice functionalities from Laravel or at least making their usage overly complicated.

Are you not sure if Laravel is the best framework for your application and you might move your application to Symfony in the future? Sure, go for the Domain and the Repository. Do you need to replace your SQL database with a NoSQL database later? Maybe it is a good justification. But do you really need it, or is it just charm?

One common argument is that the Repository helps to put some business logic into a separate layer. This normally gives me the creeps because there are better approaches for splitting your logic. Repositories are just for acting as a middle layer to connect the data layer and domain, nothing else. If you want to split your business logic, you should make use of something else — but this is another subject.

Conclusion

In conclusion, while the Repository pattern and clean architecture principles offer significant benefits in terms of maintainability and separation of concerns, their application in a Laravel context often introduces unnecessary complexity. Laravel is designed for simplicity and rapid development, and adding layers of abstraction can complicate this process.

Before implementing the Repository pattern, it is essential to evaluate your project’s specific needs. If decoupling your domain logic from Laravel’s infrastructure is a genuine necessity due to future migrations or a need for flexibility, then the complexity might be warranted. However, for many Laravel applications, leveraging Eloquent directly aligns better with the framework’s strengths and keeps the codebase simpler and more maintainable.

Ultimately, the decision should be driven by a clear understanding of your project’s requirements, balancing the trade-offs involved. Overengineering can lead to more problems than it solves, so aim to keep your solutions as straightforward as possible while still achieving your design goals. The primary objective of any architecture is to solve problems, not to create new ones.

以上是您的 Laravel 应用程序与存储库没有任何意义的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn