Storfeydd defnyddiol gydag Eloquent?

Yr wythnos diwethaf ysgrifennais erthygl am ddiwerth y templed Cadwrfa ar gyfer endidau huawdl...., fodd bynnag, addawodd ddweud wrthyf sut i'w ddefnyddio'n rhannol i'w fantais. I wneud hyn, byddaf yn ceisio dadansoddi sut mae'r templed hwn yn cael ei ddefnyddio fel arfer mewn prosiectau. Y set leiaf o ddulliau sydd eu hangen ar gyfer cadwrfa:

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

Fodd bynnag, mewn prosiectau go iawn, os penderfynir defnyddio storfeydd, mae dulliau ar gyfer adfer cofnodion yn aml yn cael eu hychwanegu atynt:

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

Gellid gweithredu'r dulliau hyn trwy sgopiau huawdl, ond nid gorlwytho dosbarthiadau endid gyda'r cyfrifoldeb o nΓ΄l eu hunain yw'r syniad gorau, ac mae symud y cyfrifoldeb hwn i ddosbarthiadau cadwrfeydd yn ymddangos yn rhesymegol. Ai felly y mae? Rhannais y rhyngwyneb hwn yn weledol yn ddwy ran yn benodol. Defnyddir rhan gyntaf y dulliau mewn gweithrediadau ysgrifennu.

Y gweithrediad ysgrifennu safonol yw:

  • adeiladu gwrthrych a her newydd Γ”l-ystorfa::cadw
  • Γ”l-ystorfa::getById, trin a gwysio endid Γ”l-ystorfa::cadw
  • her Γ”l-ystorfa:: dileu

Nid yw gweithrediadau ysgrifennu yn defnyddio dulliau nΓ΄l. Mewn gweithrediadau darllen, dim ond dulliau cael* a ddefnyddir. Os darllenwch am Egwyddor Gwahanu Rhyngwyneb (llythyr I Π² SOLET), yna bydd yn dod yn amlwg bod ein rhyngwyneb yn rhy fawr ac yn perfformio o leiaf dau gyfrifoldeb gwahanol. Mae'n bryd ei rannu Γ’ dau. Dull caelById yn angenrheidiol yn y ddau, ond wrth i'r cais ddod yn fwy cymhleth, bydd ei weithrediad yn wahanol. Byddwn yn gweld hyn ychydig yn ddiweddarach. Ysgrifennais am ddiwerth y rhan ysgrifennu mewn erthygl flaenorol, felly yn yr un hon byddaf yn anghofio amdano.

Nid yw'r rhan Read yn ymddangos mor ddiwerth i mi, oherwydd hyd yn oed i Eloquent efallai y bydd sawl gweithrediad yma. Beth i enwi'r dosbarth? Gall DarllenYstorfa, ond i'r templed Repository ychydig o berthnasedd sydd ganddo eisoes. Gallwch chi jyst Γ”l Ymholiadau:

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

Mae ei roi ar waith gydag Eloquent yn eithaf syml:

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

Rhaid i'r rhyngwyneb fod yn gysylltiedig Γ’'r gweithredu, er enghraifft yn AppServiceProvider:

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

Mae'r dosbarth hwn eisoes yn ddefnyddiol. Mae'n gwireddu ei gyfrifoldeb trwy leddfu naill ai'r rheolwyr neu'r dosbarth endid. Mewn rheolydd gellir ei ddefnyddio fel hyn:

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

Dull Rheolwr Post::lastPosts dim ond gofyn am rywfaint o weithredu Ymholiadau Post ac yn gweithio ag ef. Yn y darparwr y gwnaethom gysylltu Γ”l Ymholiadau gyda dosbarth YmholiadauPost huawdl a bydd y dosbarth hwn yn cael ei roi yn y rheolydd.

Gadewch i ni ddychmygu bod ein cais wedi dod yn boblogaidd iawn. Mae miloedd o ddefnyddwyr y funud yn agor y dudalen gyda'r cyhoeddiadau diweddaraf. Mae'r cyhoeddiadau mwyaf poblogaidd hefyd yn cael eu darllen yn aml iawn. Nid yw cronfeydd data yn trin llwythi o'r fath yn dda iawn, felly maent yn defnyddio datrysiad safonol - storfa. Yn ogystal Γ’'r gronfa ddata, mae ciplun data penodol yn cael ei storio mewn storfa wedi'i optimeiddio ar gyfer rhai gweithrediadau - memcached neu redis.

Fel arfer nid yw rhesymeg storio mor gymhleth Γ’ hynny, ond nid yw ei gweithredu yn EloquentPostQueries yn gywir iawn (os mai dim ond oherwydd Egwyddor Cyfrifoldeb Sengl). Mae'n llawer mwy naturiol defnyddio templed Addurnwr a gweithredu caching fel addurn ar gyfer y prif weithred:

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

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

Anwybyddu'r rhyngwyneb Repository yn yr adeiladydd. Am ryw reswm anhysbys, penderfynon nhw enwi'r rhyngwyneb ar gyfer caching yn Laravel fel hyn.

Dosbarth CachedPostQueries yn gweithredu caching yn unig. $this->cache->cofiwch yn gwirio a yw'r cofnod hwn yn y storfa ac os nad yw, yna'n galw'n Γ΄l ac yn ysgrifennu'r gwerth a ddychwelwyd i'r storfa. Y cyfan sydd ar Γ΄l yw gweithredu'r dosbarth hwn yn y cais. Mae arnom angen pob dosbarth sydd yn y rhaglen i ofyn am weithredu'r rhyngwyneb Γ”l Ymholiadau dechreuodd dderbyn enghraifft o'r dosbarth CachedPostQueries. Fodd bynnag, ef ei hun CachedPostQueries rhaid i'r adeiladwr dderbyn dosbarth fel paramedr YmholiadauPost huawdlgan na all weithio heb weithrediad "go iawn". Rydym yn newid 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);
    }
}

Mae fy holl ddymuniadau yn cael eu disgrifio'n eithaf naturiol yn y darparwr. Felly, fe wnaethom weithredu caching ar gyfer ein ceisiadau yn unig trwy ysgrifennu un dosbarth a newid cyfluniad y cynhwysydd. Nid yw gweddill cod y cais wedi newid.

Wrth gwrs, er mwyn gweithredu caching yn llawn, mae hefyd angen gweithredu annilysu fel nad yw'r erthygl wedi'i dileu yn hongian ar y wefan ers peth amser, ond yn cael ei dileu ar unwaith. Ond mΓ’n bethau yw'r rhain.

Gwaelod llinell: defnyddion ni nid un, ond dau dempled. Sampl Gwahanu Cyfrifoldeb Ymholiad Gorchymyn (CQRS) yn bwriadu gwahanu gweithrediadau darllen ac ysgrifennu yn gyfan gwbl ar lefel y rhyngwyneb. Deuthum ato drwodd Egwyddor Gwahanu Rhyngwyneb, sy'n awgrymu fy mod yn trin patrymau ac egwyddorion yn fedrus ac yn deillio un o'r llall fel theorem :) Wrth gwrs, nid oes angen haniaeth o'r fath ar bob prosiect ar gyfer dewis endidau, ond byddaf yn rhannu'r tric gyda chi. datblygu, gallwch yn syml greu dosbarth Γ”l Ymholiadau gyda'r gweithrediad arferol trwy Eloquent:

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

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

Pan fydd angen caching yn codi, gyda symudiad syml gallwch greu rhyngwyneb (neu ddosbarth haniaethol) yn lle'r dosbarth hwn Γ”l Ymholiadau, copΓ―wch ei weithrediad i'r dosbarth YmholiadauPost huawdl ac ewch i'r cynllun a ddisgrifiais yn gynharach. Nid oes angen newid gweddill cod y cais.

Yr holl driciau hyn gyda dosbarthiadau, rhyngwynebau, Chwistrelliad Dibyniaeth ΠΈ CQRS a ddisgrifir yn fanwl yn fy llyfr β€œArchitecture of Complex Web Applications”. Mae yna hefyd ateb i'r pos pam mae fy holl ddosbarthiadau yn yr enghreifftiau ar gyfer yr erthygl hon wedi'u nodi'n derfynol.

Ffynhonnell: hab.com

Ychwanegu sylw