>  기사  >  PHP 프레임워크  >  최근 인기 있는 Laravel 저장소 패턴(Repository)

최근 인기 있는 Laravel 저장소 패턴(Repository)

藏色散人
藏色散人앞으로
2021-11-15 15:38:302742검색

다음 튜토리얼 칼럼은 최근 인기 있는 Laravel 저장소 패턴(Repository)에서 최근 인기 있는 Laravel 저장소 패턴(Repository) 저장소 모드(Repository)에 대해 소개하겠습니다. 모든 분들께 도움이 되길 바랍니다!

2. 최근 인기 있는 Laravel 저장소 패턴(Repository)에서 리포지토리 패턴(Repository)을 사용하는 이유 ? 최근 인기 있는 Laravel 저장소 패턴(Repository)

    대부분의 웹 애플리케이션에서 데이터베이스에 액세스하는 것은 코드 베이스의 상당 부분을 차지합니다. SQL 쿼리로 인해 애플리케이션 로직이 복잡해지는 것을 방지하기 위해 우리는 PHP 메소드 뒤에 데이터 액세스 메커니즘을 숨기는 추상화에 의존합니다.
  • 구조화된 데이터 액세스에는 여러 가지 모드가 있으며, "활성 레코드"와 "저장소"가 가장 유명한 두 가지 모드입니다. 이번 블로그 포스팅에서는 최근 인기 있는 Laravel 저장소 패턴(Repository) 프레임워크의 맥락에서 구체적으로 설명하겠습니다. 리포지토리 패턴 사용의 장점과 단점에 대한 논의는 별도의 블로그 게시물에서 논의됩니다.
  • Active Record
기본적으로 최근 인기 있는 Laravel 저장소 패턴(Repository)은 Active Record 모드를 사용합니다. 모든 최근 인기 있는 Laravel 저장소 패턴(Repository) 프로그래머는 이를 직관적으로 사용합니다. 이는 모델이 일반적으로 상속하는 추상 Model 기본 클래스에서 구현되기 때문입니다. 예를 살펴보겠습니다.

use Illuminate\Database\Eloquent\Model;

/**
 * @property int    $id
 * @property string $first_name
 * @property string $last_name
 */
class Person extends Model {
}

// --- 使用:

$person = new Person();
$person->first_name = 'Jack';
$person->last_name = 'Smith';
$person->save();
물론 Person에서 생성한 속성을 읽고 쓸 수 있습니다. 하지만 모델을 저장하려면

모델에서 직접 메서드를 호출

할 수도 있습니다. 다른 객체가 필요하지 않습니다. 모델은 이미 해당 데이터베이스 테이블에 액세스하는 모든 방법을 제공합니다.

이는 도메인 모델이 사용자 정의 속성 및 메서드를 동일한 클래스의 모든 데이터 액세스 메서드와 결합한다는 것을 의미합니다. 두 번째 부분은 Model을 상속하여 구현됩니다.

핵심 포인트: Person 上创建的属性。 但是要保存模型,您也可以 直接在模型上调用方法。 不需要另一个对象——模型已经提供了访问相应数据库表的所有方法。

这意味着,域模型将您的自定义属性和方法与同一类中的所有数据访问方法相结合。 第二部分是通过继承 Model 来实现的。

要点:

  • Active Record 结合 域模型与数据访问功能。
  • 최근 인기 있는 Laravel 저장소 패턴(Repository) 使用 Active Record 模式并通过 Model 类实现它。

Repository

Repository 模式是 Active Record 模式的替代方案。它还提供了处理数据访问的抽象。但更广泛地说,它可以被视为域对象的概念性存储库或集合。

与活动记录模式相反,存储模式将数据库访问与域模型分离。它提供了一个高级接口,你可以在其中创建、读取、更新和删除域模型,而不必考虑实际的底层数据存储。

底层的存储库可以通过构建和执行 SQL 查询访问数据库,通过 REST API

활성 레코드 결합

도메인 모델과 데이터 액세스 기능.
  • 최근 인기 있는 Laravel 저장소 패턴(Repository)은 Active Record 패턴을 사용하며 Model 클래스를 통해 구현합니다.
  • Repository
  • 리포지토리 패턴은 Active Record 패턴의 대안입니다. 또한 데이터 액세스 처리를 위한 추상화도 제공합니다.
그러나 보다 광범위하게는 개념적 저장소 또는 도메인 개체 모음으로 볼 수 있습니다.

활성 레코드 패턴과 달리 저장 패턴은 데이터베이스 액세스를 도메인 모델과 분리합니다. 실제 기본 데이터 저장소에 대해 걱정할 필요 없이 도메인 모델을 생성, 읽기, 업데이트 및 삭제할 수 있는 상위 수준 인터페이스를 제공합니다.

기본 저장소는 SQL 쿼리를 작성 및 실행하여 데이터베이스에 액세스하거나, REST API를 통해 원격 시스템에 액세스하거나, 모든 도메인 모델이 포함된 메모리 내 데이터 구조를 간단히 관리할 수 있습니다. 이는 테스트에 유용합니다. 리포지토리 패턴의 핵심 부분은 나머지 코드에 제공되는 상위 수준 인터페이스입니다.

핵심 사항:

리포지토리는 도메인 개체의 개념적 컬렉션을 나타냅니다.

고수준 인터페이스로 데이터 액세스를 캡슐화하는 역할만 담당합니다.
  • 최근 인기 있는 Laravel 저장소 패턴(Repository)은 Repository 패턴 구현을 위한 특정 도우미를 제공하지 않습니다.
  • 최근 인기 있는 Laravel 저장소 패턴(Repository)에서 Repository 패턴을 구현하는 경우 주로 두 가지 변형이 보입니다.
  • 변형 1: 특정 방법
  • 첫 번째 변형에서는 저장소 방법이 집중적이고 구체적입니다. 이름은 호출자가 얻는 내용을 설명하며 기본 쿼리를 매개 변수화하는 옵션은 제한됩니다.
  • class InvoiceRepository {
    
        public function findAllOverdue(Carbon $since, int $limit = 10): Collection {
            return Invoice::where('overdue_since', '>=', $since)
                ->limit($limit)
                ->orderBy('overdue_since')
                ->get();
        }
    
        public function findInvoicedToCompany(string $companyId): Collection {
            return Invoice::where('company_id', $companyId)
                ->orderByDesc('created_at')
                ->get();
        }
    }
    이 방식의 장점은 방식의 표현력이다. 코드를 읽을 때 메서드에서 무엇을 기대할 수 있는지, 메서드를 호출하는 방법이 명확해집니다. 결과적으로 오류가 줄어듭니다. 리포지토리 메서드는 매개변수가 제한되어 있으므로 테스트하기 쉽습니다.
  • 이 접근 방식의 한 가지 단점은 저장소에서 많은 수의 메서드를 사용하게 될 수 있다는 것입니다. 메소드는 쉽게 재사용할 수 없으므로 새로운 사용 사례를 위해서는 추가 메소드를 추가해야 합니다.

포인트:

스토리지 스키마는 특정 메서드를 제공하는 클래스로 구현할 수 있습니다.

각 메서드는 쿼리를 래핑하여 필요한 매개변수만 노출합니다.

🎜장점:🎜가독성 및 테스트 가능성🎜🎜🎜 단점: 🎜 유연성 부족 및 낮은 재사용성 🎜🎜🎜변형 2: 일반 방법 🎜🎜 반면에 접근 방식은 일반적인 방법을 제공하는 것입니다. 이로 인해 방법이 감소했습니다. 🎜그러나 이러한 메서드는 API 표면이 넓습니다🎜. 각 메서드는 다양한 매개변수 조합으로 호출될 수 있기 때문입니다. 🎜🎜🎜핵심 문제는 매개변수 표현🎜입니다. 이 표현은 호출자가 메서드 서명을 이해하도록 안내하고 잘못된 입력을 방지해야 합니다. 이를 위해 쿼리 개체 패턴 등을 사용하여 특수 클래스를 도입할 수 있습니다. 🎜

但是我在实践中经常看到的是标量参数和 PHP 数组的混合。调用方可以传递完全无效的输入,仅类型数据并不能说明要传递什么。但是如果使用得当,这种轻量级的方法可以避免更繁琐的抽象。

class InvoiceRepository {

    public function find(array $conditions, string $sortBy = 'id', string $sortOrder = 'asc', int $limit = 10): Collection {
        return Invoice::where($conditions)
            ->orderBy($sortBy, $sortOrder)
            ->limit($limit)
            ->get();
    }
}

// --- 使用:

$repo = new InvoiceRepository();
$repo->find(['overdue_since', '>=', $since], 'overdue_since', 'asc');
$repo->find(['company_id', '=', $companyId], 'created_at', 'asc', 100);

这种方法减轻了第一种方法的问题:你可以得到更少的 Repository 方法,这些方法更灵活,并且可以更频繁地重用。

从消极的方面看,Repository 变得更加难以测试,因为有更多的案例需要覆盖。方法签名更难理解,正因为如此,调用者可能会犯更多错误。此外,还将引入某种查询对象表示形式。无论它是显式的还是隐式的(比如数组),您的 Repository 实现及其调用者都将与它耦合。

要点:

  • 存储库模式可以通过提供通用方法的类实现。
  • 难点在于方法参数的表示。
  • 优点: 更大的灵活性和更高的可复用性。
  • 缺点: 更难测试,可读性差,与参数表示耦合。

当然,这两种方法可以结合起来使用。也许你想要一些特定的方法用于复杂的查询,而一些通用的方法用于简单的 where 查询。

实现

现在,我们来谈谈如何实现方法体。

在上面的例子中,我使用了 Model 类的方法来获得对 Eloquent 查询构造器的访问。所以 Repository 的实现实际上使用了 Active Record 模式作为实现。

你不需要这样做。你可以使用 DB facade 来获得一个查询构建器,同时避免使用 Model 类。或者你可以直接编写 SQL 查询:

class InvoiceRepository {

    public function findAllOverdue(Carbon $since, int $limit = 10): Collection {
        return DB::table('invoices')
            ->where('overdue_since', '>=', $since)
            ->limit($limit)
            ->orderBy('overdue_since')
            ->get();
    }

    public function findInvoicedToCompany(string $companyId): Collection {
        return DB::select('SELECT * FROM invoices
                           WHERE company_id = ?
                           ORDER BY created_at
                           LIMIT 100', [$companyId]);
    }
}

存储模式的优点是,实现可以是任何东西,只要它满足接口。你还可以管理内存中的对象或者包(和缓存)一个 API。

但是最常见的是,底层数据存储是一个 SQL 数据库。要访问它,你可以根据每个方法选择最佳实现。对于性能关键的或者复杂的查询,你可能希望直接使用 SQL 语句。更简单的查询可以使用 Eloquent 查询生成器。

当你没有使用 模型 类来实现你的 Repository ,你可能会考虑在模型中不继承它。但是这个方法违反了很多内置的 최근 인기 있는 Laravel 저장소 패턴(Repository) 魔术方法,在我看来并不是一个好的方法。

要点:

  • 存储库模式很灵活,允许使用各种实现技术。
  • 在 최근 인기 있는 Laravel 저장소 패턴(Repository) 中,当访问数据库时,Eloquent 查询构建器是一个实用的选择。

接口

你的另一个选择是,是否要引入一个接口。上面的例子可以用一个接口和一个或多个实现来分隔:

// --- 接口:

public interface InvoiceRepositoryInterface {

    public function findAllOverdue(Carbon $since, int $limit = 10): Collection;

    public function findInvoicedToCompany(string $companyId): Collection;
}

// --- 具体的类,实现了该接口

class InvoiceRepository implements InvoiceRepositoryInterface {

    public function findAllOverdue(Carbon $since, int $limit = 10): Collection {
        // 实现
    }

    public function findInvoicedToCompany(string $companyId): Collection {
        // 实现
    }
}

添加接口是一种额外的间接方法,并不一定是好的。如果您的应用程序是 Repository 的唯一用户,并且您不希望它有多个实现,那么我不认为引入接口有什么意义。对于测试,Repository 可以用 PHPUnit 模拟,只要它不被标记为 final

如果你知道你将有多个实现,你应该使用一个接口。如果你正在编写一个将在多个项目中使用的 包。或者你想要测试一个特殊的 Repository 实现,那么可能会发生不同的实现。

为了从 최근 인기 있는 Laravel 저장소 패턴(Repository) 的依赖注入中获益,你必须将具体的实现绑定到接口上。这必须在服务提供者的注册方法中完成。

use Illuminate\Support\ServiceProvider;

class RepositoryServiceProvider extends ServiceProvider {

    public function register(): void {
        $this->app->bind(InvoiceRepositoryInterface::class, InvoiceRepository::class);
    }
}

要点:

  • 一个接口可以进一步 解耦 从代码的其余部分获取代码库。
  •  当您期望有多个具体类实现它时,使用 Repository 接口。
  • 在 최근 인기 있는 Laravel 저장소 패턴(Repository) 中,将具体类绑定到服务提供者中的接口。

原文地址:https://dev.to/davidrjenni/repository-pattern-in-laravel-1pph

译文地址:https://learnku.com/laravel/t/62587

위 내용은 최근 인기 있는 Laravel 저장소 패턴(Repository)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제