Noderīgas krātuves ar Eloquent?

PagājuÅ”ajā nedēļā es rakstÄ«ju raksts par repozitorija veidnes nederÄ«gumu Eloquent entÄ«tijāmtomēr viņŔ apsolÄ«ja man pastāstÄ«t, kā to daļēji izmantot savā labā. Lai to izdarÄ«tu, es mēģināŔu analizēt, kā Ŕī veidne parasti tiek izmantota projektos. Repozitorija minimālais nepiecieÅ”amais metožu kopums:

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

Tomēr reālos projektos, ja tika nolemts izmantot repozitorijus, tiem bieži tiek pievienotas ierakstu izguves metodes:

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

Å Ä«s metodes varētu ieviest, izmantojot Eloquent tvērumus, taču pārslogot entÄ«tiju klases, uzņemoties paÅ”as par sevi, nav labākā ideja, un Ŕīs atbildÄ«bas pārvietoÅ”ana uz repozitoriju klasēm Ŕķiet loÄ£iska. Vai tā ir? Es Ä«paÅ”i vizuāli sadalÄ«ju Å”o saskarni divās daļās. Pirmā metožu daļa tiks izmantota rakstīŔanas operācijās.

Standarta rakstīŔanas darbība ir Ŕāda:

  • jauna objekta celtniecÄ«ba un izaicinājums PostRepository::save
  • PostRepository::getById, entÄ«tiju manipulācijas un izsaukÅ”ana PostRepository::save
  • izaicinājums PostRepository::delete

RakstīŔanas operācijās netiek izmantotas ielādes metodes. LasīŔanas operācijās tiek izmantotas tikai get* metodes. Ja lasi par Interfeisa segregācijas princips (vēstule I в SOLID), tad kļūs skaidrs, ka mÅ«su saskarne ir pārāk liela un veic vismaz divus dažādus pienākumus. Ir pienācis laiks to sadalÄ«t ar diviem. Metode getById ir nepiecieÅ”ama abos, taču, lietojumprogrammai kļūstot sarežģītākai, tās ievieÅ”anas bÅ«s atŔķirÄ«gas. To mēs redzēsim nedaudz vēlāk. Es rakstÄ«ju par rakstīŔanas daļas bezjēdzÄ«bu iepriekŔējā rakstā, tāpēc Å”ajā es par to vienkārÅ”i aizmirsīŔu.

LasīŔanas daļa man neŔķiet tik bezjēdzÄ«ga, jo pat Eloquent Å”eit var bÅ«t vairākas ievieÅ”anas. Kā nosaukt klasi? Var ReadPostRepository, bet uz veidni Krātuve viņam jau ir maza nozÄ«me. JÅ«s varat vienkārÅ”i PostQuerys:

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

To ieviest ar Eloquent ir pavisam vienkārŔi:

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

Saskarnei jābÅ«t saistÄ«tai ar ievieÅ”anu, piemēram, in AppServiceProvider:

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

Å Ä« klase jau ir noderÄ«ga. ViņŔ apzinās savu atbildÄ«bu, atbrÄ«vojot vai nu kontrolierus, vai entÄ«tiju klasi. KontrolerÄ« to var izmantot Ŕādi:

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

Metode PostsController::lastPosts tikai prasu kādu ievieÅ”anu PostsQuerys un strādā ar to. MÅ«su piesaistÄ«tajā pakalpojumu sniedzējā PostQuerys ar klasi EloquentPostQueries un Ŕī klase tiks aizstāta ar kontrolieri.

Iedomāsimies, ka mÅ«su aplikācija ir kļuvusi ļoti populāra. TÅ«kstoÅ”iem lietotāju minÅ«tē atver lapu ar jaunākajām publikācijām. Ä»oti bieži tiek lasÄ«tas arÄ« populārākās publikācijas. Datu bāzes ar Ŕādām slodzēm netiek galā Ä«paÅ”i labi, tāpēc izmanto standarta risinājumu – keÅ”atmiņu. Papildus datu bāzei noteikts datu momentuzņēmums tiek glabāts krātuvē, kas ir optimizēts noteiktām darbÄ«bām - memcached vai Redis.

KeÅ”atmiņas loÄ£ika parasti nav tik sarežģīta, taču tās ievieÅ”ana programmā EloquentPostQueries nav pārāk pareiza (ja tikai tāpēc, ka Vienotas atbildÄ«bas princips). Daudz dabiskāk ir izmantot veidni Dekorators un ieviest keÅ”atmiņu kā galvenās darbÄ«bas noformējumu:

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

    // Š“Ń€ŃƒŠ³ŠøŠµ метоГы практически такие же
}

Ignorējiet saskarni Krātuve konstruktorā. Nezināma iemesla dēļ viņi nolēma Ŕādi nosaukt Laravel keÅ”atmiņas interfeisu.

Klase CachedPostQueries ievieÅ” tikai keÅ”atmiņu. $this->cache->atcerēties pārbauda, ​​vai Å”is ieraksts ir keÅ”atmiņā un ja nav, tad izsauc atzvanīŔanu un ieraksta atgriezto vērtÄ«bu keÅ”atmiņā. Atliek tikai ieviest Å”o klasi lietojumprogrammā. Mums ir vajadzÄ«gas visas lietojumprogrammas klases, lai pieprasÄ«tu saskarnes ievieÅ”anu PostQuerys sāka saņemt klases piemēru CachedPostQueries. Tomēr viņŔ pats CachedPostQueries konstruktoram kā parametrs jāsaņem klase EloquentPostQueriesjo tas nevar darboties bez "Ä«stas" ievieÅ”anas. Mēs maināmies 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);
    }
}

Visas manas vēlmes ir diezgan dabiski aprakstÄ«tas pakalpojumu sniedzējā. Tādējādi mēs ieviesām keÅ”atmiņu saviem pieprasÄ«jumiem, tikai rakstot vienu klasi un mainot konteinera konfigurāciju. Pārējais lietojumprogrammas kods nav mainÄ«jies.

Protams, lai pilnÄ«bā ieviestu keÅ”atmiņu, ir jāievieÅ” arÄ« nederÄ«ba, lai dzēstais raksts kādu laiku nekarātos vietnē, bet tiktu nekavējoties izdzēsts. Bet tās ir mazsvarÄ«gas lietas.

Secinājums: mēs izmantojām nevis vienu, bet divas veidnes. Paraugs Command Query Responsibility Segregation (CQRS) ierosina pilnÄ«bā nodalÄ«t lasīŔanas un rakstīŔanas darbÄ«bas saskarnes lÄ«menÄ«. Es nonācu pie viņa caur Interfeisa segregācijas princips, kas liek domāt, ka es prasmÄ«gi manipulēju ar modeļiem un principiem un atvasinu vienu no otra kā teorēmu :) Protams, ne katram projektam ir vajadzÄ«ga Ŕāda entÄ«tiju atlases abstrakcija, bet es padalīŔos ar jums. attÄ«stÄ«bu, varat vienkārÅ”i izveidot klasi PostQuerys ar parasto ievieÅ”anu, izmantojot Eloquent:

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

    // Š“Ń€ŃƒŠ³ŠøŠµ метоГы
}

Kad rodas vajadzÄ«ba pēc keÅ”atmiņas, ar vienkārÅ”u pārvietoÅ”anu varat izveidot interfeisu (vai abstraktu klasi) Ŕīs klases vietā PostQuerys, kopējiet tā ievieÅ”anu klasē EloquentPostQueries un dodieties uz iepriekÅ” aprakstÄ«to shēmu. Pārējais lietojumprogrammas kods nav jāmaina.

Visi Å”ie triki ar klasēm, saskarnēm, AtkarÄ«bas injekcija Šø CQRS detalizēti aprakstÄ«ts mana grāmata ā€œSarežģītu tÄ«mekļa lietojumprogrammu arhitektÅ«raā€. Ir arÄ« risinājums mÄ«klai, kāpēc visas manas nodarbÄ«bas Ŕī raksta piemēros ir atzÄ«mētas kā galÄ«gas.

Avots: www.habr.com

Iegādājieties uzticamu mitināŔanu vietnēm ar DDoS aizsardzÄ«bu, VPS VDS serveriem šŸ”„ Iegādājieties uzticamu tÄ«mekļa vietņu mitināŔanu ar DDoS aizsardzÄ«bu, VPS VDS serveriem | ProHoster