Mapuslanon nga mga repository nga adunay Eloquent?

Sa miaging semana nagsulat ko artikulo bahin sa pagkawalay kapuslanan sa template sa Repository alang sa Eloquent entities, bisan pa niana, misaad siya nga sultihan ko kon unsaon paggamit niini sa bahin sa iyang kaayohan. Aron mahimo kini, sulayan nako nga analisahon kung giunsa kini nga template kasagarang gigamit sa mga proyekto. Ang minimum nga gikinahanglan nga set sa mga pamaagi alang sa usa ka repository:

<?php
interface PostRepository
{
    public function getById($id): Post;
    public function save(Post $post);
    public function delete($id);
}

Bisan pa, sa tinuud nga mga proyekto, kung nakahukom nga gamiton ang mga repository, ang mga pamaagi sa pagkuha sa mga rekord kanunay nga idugang kanila:

<?php
interface PostRepository
{
    public function getById($id): Post;
    public function save(Post $post);
    public function delete($id);

    public function getLastPosts();
    public function getTopPosts();
    public function getUserPosts($userId);
}

Kini nga mga pamaagi mahimong ipatuman pinaagi sa Eloquent scopes, apan ang pag-overload sa mga klase sa entidad nga adunay responsibilidad sa pagkuha sa ilang mga kaugalingon dili ang labing kaayo nga ideya, ug ang pagbalhin niini nga responsibilidad sa mga klase sa repositoryo daw makatarunganon. Mao ba? Espesyal nga gibahin nako kini nga interface sa duha ka bahin. Ang unang bahin sa mga pamaagi gamiton sa pagsulat nga mga operasyon.

Ang standard nga operasyon sa pagsulat mao ang:

  • pagtukod sa usa ka bag-ong butang ug hagit PostRepository:: save
  • PostRepository::getById, pagmaniobra sa entidad ug pagpatawag PostRepository:: save
  • ang hagit PostRepository::pagtangtang

Ang mga operasyon sa pagsulat wala mogamit mga pamaagi sa pagkuha. Sa read operations, get* lang ang mga pamaagi ang gigamit. Kung magbasa ka bahin sa Prinsipyo sa Pagbulag sa Interface (sulat I Π² SOLID), unya kini mahimong tin-aw nga ang among interface dako kaayo ug naghimo sa labing menos duha ka lainlaing mga responsibilidad. Panahon na nga bahinon kini sa duha. Pamaagi getById gikinahanglan sa duha, apan samtang ang aplikasyon nahimong mas komplikado, ang mga pagpatuman niini magkalahi. Atong makita kini sa ulahi. Gisulat ko ang bahin sa pagkawalay kapuslanan sa bahin sa pagsulat sa usa ka miaging artikulo, mao nga niining usa kalimtan ra nako kini.

Ang bahin sa Pagbasa ingon alang kanako dili kaayo kapuslan, tungod kay bisan alang sa Eloquent mahimong adunay daghang mga pagpatuman dinhi. Unsay ingalan sa klase? Mahimo ReadPostRepository, apan sa template Repository gamay ra na siyag kalambigitan. Mahimo ra nimo Mga PostQuery:

<?php
interface PostQueries
{
    public function getById($id): Post;
    public function getLastPosts();
    public function getTopPosts();
    public function getUserPosts($userId);
}

Ang pagpatuman niini sa Eloquent yano ra:

<?php
final class EloquentPostQueries implements PostQueries
{
    public function getById($id): Post
    {
        return Post::findOrFail($id);
    }

    /**
    * @return Post[] | Collection
    */
    public function getLastPosts()
    {
        return Post::orderBy('created_at', 'desc')
            ->limit(/*some limit*/)
            ->get();
    }
    /**
    * @return Post[] | Collection
    */
    public function getTopPosts()
    {
        return Post::orderBy('rating', 'desc')
            ->limit(/*some limit*/)
            ->get();
    }

    /**
    * @param int $userId
    * @return Post[] | Collection
    */
    public function getUserPosts($userId)
    {
        return Post::whereUserId($userId)
            ->orderBy('created_at', 'desc')
            ->get();
    }
}

Ang interface kinahanglan nga nalangkit sa pagpatuman, pananglitan sa AppServiceProvider:

<?php
final class AppServiceProvider extends ServiceProvider 
{
    public function register()
    {
        $this->app->bind(PostQueries::class, 
            EloquentPostQueries::class);
    }
}

Kini nga klase mapuslanon na. Naamgohan niya ang iyang responsibilidad pinaagi sa paghupay sa mga tigkontrol o sa klase sa entidad. Sa usa ka controller kini mahimong gamiton sama niini:

<?php
final class PostsController extends Controller
{
    public function lastPosts(PostQueries $postQueries)
    {
        return view('posts.last', [
            'posts' => $postQueries->getLastPosts(),
        ]);
    }
} 

Paagi PostsController::lastPosts nangayo lang ug implementasyon Mga Pangutana sa Post ug nagtrabaho uban niini. Sa provider nga among gi-link Mga PostQuery uban sa klase EloquentPostQueries ug kini nga klase ilisan sa controller.

Hunahunaa nga ang among aplikasyon nahimong popular kaayo. Liboan ka mga tiggamit matag minuto ang nagbukas sa panid nga adunay labing bag-ong mga publikasyon. Ang labing inila nga mga publikasyon kanunay usab nga gibasa. Ang mga database dili maayo nga pagdumala sa ingon nga mga karga, mao nga gigamit nila ang usa ka sumbanan nga solusyon - usa ka cache. Dugang pa sa database, ang usa ka piho nga snapshot sa datos gitipigan sa pagtipig nga na-optimize alang sa pipila nga mga operasyon - nagmcached o repeat.

Ang lohika sa pag-cache kasagaran dili ingon ka komplikado, apan ang pagpatuman niini sa EloquentPostQueries dili kaayo husto (kung tungod lang kay Single nga Baruganan sa Responsibilidad). Mas natural ang paggamit ug template Dekorador ug ipatuman ang caching isip dekorasyon alang sa nag-unang aksyon:

<?php
use IlluminateContractsCacheRepository;

final class CachedPostQueries implements PostQueries
{
    const LASTS_DURATION = 10;

    /** @var PostQueries */
    private $base;

    /** @var Repository */
    private $cache;

    public function __construct(
        PostQueries $base, Repository $cache) 
    {
        $this->base = $base;
        $this->cache = $cache;
    }

    /**
    * @return Post[] | Collection
    */
    public function getLastPosts()
    {
        return $this->cache->remember('last_posts', 
            self::LASTS_DURATION, 
            function(){
                return $this->base->getLastPosts();
            });
    }

    // Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ практичСски Ρ‚Π°ΠΊΠΈΠ΅ ΠΆΠ΅
}

Ibaliwala ang interface Repository sa constructor. Sa wala mahibal-i nga hinungdan, nakahukom sila nga hinganlan ang interface alang sa pag-cache sa Laravel niining paagiha.

Класс CachedPostQueries nagpatuman lamang sa caching. $this->cache->hinumdomi susihon kung kini nga entry naa sa cache ug kung wala, unya tawagan ang callback ug isulat ang gibalik nga kantidad sa cache. Ang nahabilin mao ang pagpatuman niini nga klase sa aplikasyon. Kinahanglan namon ang tanan nga mga klase nga sa aplikasyon aron mangayo usa ka pagpatuman sa interface Mga PostQuery nagsugod sa pagdawat og usa ka pananglitan sa klase CachedPostQueries. Hinuon, siya mismo CachedPostQueries ang constructor kinahanglang makadawat ug klase isip parameter EloquentPostQueriestungod kay dili kini molihok kung wala ang "tinuod" nga pagpatuman. Nagbag-o mi AppServiceProvider:

<?php
final class AppServiceProvider extends ServiceProvider 
{
    public function register()
    {
        $this->app->bind(PostQueries::class, 
            CachedPostQueries::class);

        $this->app->when(CachedPostQueries::class)
            ->needs(PostQueries::class)
            ->give(EloquentPostQueries::class);
    }
}

Ang tanan nakong mga pangandoy natural nga gihulagway sa provider. Busa, gipatuman namo ang caching alang sa among mga hangyo pinaagi lamang sa pagsulat og usa ka klase ug pag-usab sa configuration sa sudlanan. Ang nahabilin nga code sa aplikasyon wala mausab.

Siyempre, aron hingpit nga ipatuman ang caching, gikinahanglan usab nga ipatuman ang pagka-invalidation aron ang natangtang nga artikulo dili magbitay sa site sulod sa pipila ka panahon, apan mapapas dayon. Apan kini mga gagmay nga butang.

Ubos nga linya: wala namo gigamit ang usa, apan duha ka templates. Sampol Command Query Responsibility Segregation (CQRS) nagsugyot sa hingpit nga pagbulag sa pagbasa ug pagsulat nga mga operasyon sa lebel sa interface. Giduol nako siya pinaagi Prinsipyo sa Pagbulag sa Interface, nga nagsugyot nga ako hanas nga nagmaniobra sa mga sumbanan ug mga prinsipyo ug nagkuha sa usa gikan sa usa ingon nga usa ka teorama :) Siyempre, dili tanan nga proyekto nagkinahanglan sa ingon nga abstraction alang sa pagpili sa mga entidad, apan akong ipaambit ang limbong uban kanimo.Sa inisyal nga yugto sa aplikasyon pag-uswag, mahimo ka lang maghimo usa ka klase Mga PostQuery uban ang naandan nga pagpatuman pinaagi sa Eloquent:

<?php
final class PostQueries
{
    public function getById($id): Post
    {
        return Post::findOrFail($id);
    }

    // Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹
}

Kung ang panginahanglan alang sa pag-cache mitungha, sa usa ka yano nga paglihok mahimo ka makahimo usa ka interface (o abstract nga klase) puli niini nga klase Mga PostQuery, kopyaha ang pagpatuman niini ngadto sa klase EloquentPostQueries ug adto sa laraw nga akong gihulagway sa sayo pa. Ang nahabilin nga code sa aplikasyon dili kinahanglan nga usbon.

Tanan kini nga mga limbong nga adunay mga klase, interface, Pagdugang sa Pagdugang ΠΈ CQRS gihulagway sa detalye sa akong libro nga "Arkitektura sa Komplikadong Mga Aplikasyon sa Web". Adunay usab usa ka solusyon sa tigmo ngano nga ang tanan nakong mga klase sa mga panig-ingnan alang niini nga artikulo gimarkahan nga katapusan.

Source: www.habr.com

Idugang sa usa ka comment