Repositori sing migunani karo Eloquent?

Minggu kepungkur aku nulis artikel babagan ora ana gunane template Repositori kanggo entitas Eloquent, Nanging, dheweke janji marang kula carane sebagian nggunakake kanggo kauntungan. Kanggo nindakake iki, aku bakal nyoba nganalisa kepiye cithakan iki biasane digunakake ing proyek. Cara minimal sing dibutuhake kanggo repositori:

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

Nanging, ing proyek nyata, yen diputusake nggunakake repositori, cara kanggo njupuk cathetan asring ditambahake:

<?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);
}

Cara iki bisa dileksanakake liwat scopes Eloquent, nanging overloading kelas entitas karo tanggung jawab njupuk dhewe ora idea paling apik, lan mindhah tanggung jawab iki kanggo kelas repositori katon logis. Apa iya? Aku khusus visual dibagi antarmuka iki dadi rong bagΓ©an. Bagian pisanan saka metode kasebut bakal digunakake ing operasi nulis.

Operasi nulis standar yaiku:

  • construction saka obyek anyar lan tantangan PostRepository:: simpen
  • PostRepository::getById, manipulasi entitas lan panggilan PostRepository:: simpen
  • tantangan PostRepository:: mbusak

Operasi nulis ora nggunakake cara njupuk. Ing operasi sing diwaca, mung metode get * sing digunakake. Yen maca babagan Prinsip Segregasi Antarmuka (layang I Π² SOLID), banjur bakal dadi cetha manawa antarmuka kita gedhe banget lan nindakake paling ora rong tanggung jawab sing beda. Wektu kanggo dibagi dadi loro. Metode getById perlu ing loro, nanging minangka aplikasi dadi luwih Komplek, implementasine bakal beda. Kita bakal weruh iki sethitik mengko. Aku nulis babagan ora ana gunane bagean nulis ing artikel sadurunge, mula aku bakal lali babagan iki.

Bagian Read misale jek ora ana gunane, amarga sanajan kanggo Eloquent bisa uga ana sawetara implementasine ing kene. Apa jeneng kelas? Saget ReadPostRepository, nanging kanggo cithakan Repository dheweke wis duwe relevansi sethithik. Sampeyan mung bisa PostQueries:

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

Ngleksanakake karo Eloquent cukup prasaja:

<?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();
    }
}

Antarmuka kudu digandhengake karo implementasine, contone ing AppServiceProvider:

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

Kelas iki wis migunani. Dheweke nyadari tanggung jawabe kanthi ngilangi pengontrol utawa kelas entitas. Ing controller bisa digunakake kaya iki:

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

Cara PostsController:: lastPosts mung takon sawetara implementasine PostsQueries lan dianggo karo. Ing panyedhiya kita disambungake PostQueries karo kelas EloquentPostQueries lan kelas iki bakal diganti menyang controller.

Bayangake manawa aplikasi kita wis populer banget. Ewonan pangguna saben menit mbukak kaca kanthi publikasi paling anyar. Publikasi sing paling populer uga asring diwaca. Basis data ora nangani beban kasebut kanthi apik, mula nggunakake solusi standar - cache. Saliyane ing basis data, snapshot data tartamtu disimpen ing panyimpenan sing dioptimalake kanggo operasi tartamtu - memcached utawa redis.

Logika cache biasane ora rumit, nanging ngetrapake ing EloquentPostQueries ora bener (yen mung amarga Prinsip Tanggung jawab Tunggal). Luwih alami nggunakake cithakan Dekorator lan ngleksanakake caching minangka hiasan kanggo tumindak utama:

<?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();
            });
    }

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

Nglirwakake antarmuka Repository ing konstruktor. Kanggo sawetara alasan sing ora dingerteni, dheweke mutusake kanggo menehi jeneng antarmuka kanggo caching ing Laravel kanthi cara iki.

Класс CachedPostQueries mung ngleksanakake caching. $this->cache->eling mriksa apa entri iki ana ing cache lan yen ora, banjur nelpon callback lan nulis nilai bali menyang cache. Kabeh sing isih ana yaiku ngetrapake kelas iki ing aplikasi kasebut. We kudu kabeh kelas sing ing aplikasi kanggo njaluk implementasine saka antarmuka PostQueries wiwit nampa conto saka kelas CachedPostQueries. Nanging, dheweke dhewe CachedPostQueries konstruktor kudu nampa kelas minangka parameter EloquentPostQueriesawit iku ora bisa tanpa implementasine "nyata". We ngganti 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);
    }
}

Kabeh kepinginanku cukup alami diterangake ing panyedhiya. Mangkono, kita ngleksanakake caching kanggo panjalukan kita mung kanthi nulis siji kelas lan ngganti konfigurasi wadhah. Kode aplikasi liyane ora diganti.

Mesthi, kanggo ngleksanakake caching kanthi lengkap, uga perlu kanggo ngleksanakake invalidation supaya artikel sing wis dibusak ora macet ing situs kanggo sawetara wektu, nanging langsung dibusak. Nanging iki minangka perkara cilik.

Bottom line: kita nggunakake ora siji, nanging loro cithakan. Sampel Command Query Responsibility Segregation (CQRS) ngusulake kanggo rampung misahake operasi maca lan nulis ing tingkat antarmuka. Aku teka marang liwat Prinsip Segregasi Antarmuka, sing nuduhake yen aku trampil ngapusi pola lan prinsip lan nurunake siji saka liyane minangka teorema :) Mesthine, ora saben proyek mbutuhake abstraksi kasebut kanggo milih entitas, nanging aku bakal nuduhake trik kasebut karo sampeyan. Ing tahap awal aplikasi pembangunan, sampeyan mung bisa nggawe kelas PostQueries kanthi implementasine biasa liwat Eloquent:

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

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

Yen perlu kanggo caching, kanthi gerakan prasaja sampeyan bisa nggawe antarmuka (utawa kelas abstrak) ing panggonan kelas iki. PostQueries, nyalin implementasine menyang kelas EloquentPostQueries lan pindhah menyang skema sing dakkandhakake sadurunge. Kode aplikasi liyane ora perlu diganti.

Kabeh trik iki nganggo kelas, antarmuka, Injeksi ketergantungan ΠΈ CQRS diterangake kanthi rinci ing bukuku "Arsitektur Aplikasi Web Kompleks". Ana uga solusi teka-teki kenapa kabeh kelasku ing conto artikel iki ditandhani minangka final.

Source: www.habr.com

Add a comment