Repozitwa itil ak Eloquent?

Semèn pase a mwen te ekri atik sou initilite modèl Repository pou antite Elokan, sepandan, li te pwomèt pou di m 'ki jan yo pasyèlman itilize li nan avantaj li. Pou fè sa, mwen pral eseye analize ki jan modèl sa a anjeneral yo itilize nan pwojè yo. Seri minimòm metòd obligatwa pou yon depo:

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

Sepandan, nan pwojè reyèl, si li te deside sèvi ak depo, metòd pou rekipere dosye yo souvan ajoute nan yo:

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

Metòd sa yo ta ka aplike atravè Eloquent Scopes, men Surcharge klas antite ak responsablite pou yo chache tèt yo se pa pi bon lide, epi deplase responsablite sa a nan klas depo sanble lojik. Eske se konsa? Mwen espesyalman vizyèlman divize koòdone sa a an de pati. Premye pati nan metòd yo pral itilize nan operasyon ekri.

Operasyon ekri estanda se:

  • konstriksyon yon nouvo objè ak defi PostRepository::save
  • PostRepository::getById, manipilasyon antite ak konvokasyon PostRepository::save
  • yon defi PostRepository::delete

Operasyon ekriti yo pa itilize metòd chache. Nan operasyon lekti, yo itilize sèlman metòd get*. Si ou li sou Prensip Segregasyon Entèfas (lèt I в SOLID), Lè sa a, li pral vin klè ke koòdone nou an twò gwo epi fè omwen de responsablite diferan. Li lè yo divize li pa de. Metòd getById li nesesè nan tou de, men kòm aplikasyon an vin pi konplèks, aplikasyon li yo pral diferan. Nou pral wè sa yon ti kras pita. Mwen te ekri sou initilite pati ekri a nan yon atik anvan, kidonk nan yon sèl sa a mwen pral tou senpleman bliye sou li.

Pati Li a sanble pa tèlman initil, paske menm pou Eloquent ka gen plizyè aplikasyon isit la. Ki non klas la? Kapab ReadPostRepository, men nan modèl la Repository li deja gen ti enpòtans. Ou ka jis PostQueries:

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

Aplike li ak Eloquent se byen senp:

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

Koòdone a dwe asosye ak aplikasyon an, pou egzanp nan AppServiceProvider:

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

Klas sa deja itil. Li reyalize responsablite li pa soulaje swa kontwolè yo oswa klas antite. Nan yon kontwolè li ka itilize jan sa a:

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

Metòd PostsController::lastPosts jis mande pou kèk aplikasyon PostsQueries epi travay avèk li. Nan founisè a nou konekte PostQueries ak klas EloquentPostQueries epi klas sa a pral ranplase nan kontwolè a.

Ann imajine ke aplikasyon nou an te vin trè popilè. Dè milye de itilizatè pa minit louvri paj la ak dènye piblikasyon yo. Piblikasyon ki pi popilè yo tou li trè souvan. Baz done pa okipe chay sa yo trè byen, kidonk yo sèvi ak yon solisyon estanda - yon kachèt. Anplis de baz done a, se yon sèten snapshot done ki estoke nan depo optimize pou operasyon sèten - memcached oswa di ankò.

Lojik kachèt anjeneral pa tèlman konplike, men aplike li nan EloquentPostQueries pa trè kòrèk (si sèlman paske Prensip Responsablite Single). Li pi natirèl pou itilize yon modèl Dekoratè epi aplike kachèt kòm dekorasyon pou aksyon prensipal la:

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

    // другие методы практически такие же
}

Inyore koòdone a Repository nan konstrukteur la. Pou kèk rezon enkoni, yo deside non koòdone a pou kachèt nan Laravel fason sa a.

Gwoup CachedPostQueries aplike kachèt sèlman. $sa->kachèt->sonje tcheke si antre sa a nan kachèt la epi si se pa sa, Lè sa a, rele callback epi ekri valè a retounen nan kachèt la. Tout sa ki rete se aplike klas sa a nan aplikasyon an. Nou bezwen tout klas ki nan aplikasyon an pou mande yon aplikasyon koòdone a PostQueries te kòmanse resevwa yon egzanp nan klas la CachedPostQueries. Sepandan, li menm CachedPostQueries konstrukteur a dwe resevwa yon klas kòm yon paramèt EloquentPostQueriesdepi li pa ka travay san yon aplikasyon "reyèl". Nou chanje 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);
    }
}

Tout volonte mwen yo byen natirèlman dekri nan founisè a. Kidonk, nou aplike kachèt pou demann nou yo sèlman lè nou ekri yon klas epi chanje konfigirasyon veso a. Rès kòd aplikasyon an pa chanje.

Natirèlman, pou aplike totalman kachèt, li nesesè tou aplike envalidasyon pou atik la efase pa kwoke sou sit la pou kèk tan, men li efase imedyatman. Men, sa yo se bagay minè.

Anba liy: nou te itilize pa youn, men de modèl. Egzanp Segregasyon Responsablite Rekèt kòmand (CQRS) pwopoze konplètman separe operasyon lekti ak ekri nan nivo koòdone. Mwen te vin jwenn li atravè Prensip Segregasyon Entèfas, ki sijere ke mwen abilman manipile modèl ak prensip ak derive youn nan lòt la kòm yon teyorèm :) Natirèlman, se pa tout pwojè bezwen tankou yon abstrè pou chwazi antite, men mwen pral pataje jwe fent la avèk ou. Nan etap inisyal aplikasyon an. devlopman, ou ka tou senpleman kreye yon klas PostQueries ak aplikasyon abityèl la atravè Eloquent:

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

    // другие методы
}

Lè bezwen pou kachèt rive, ak yon mouvman senp ou ka kreye yon koòdone (oswa klas abstrè) nan plas klas sa a. PostQueries, kopye aplikasyon li nan klas la EloquentPostQueries epi ale nan konplo a mwen te dekri pi bonè. Rès kòd aplikasyon an pa bezwen chanje.

Tout ke trik nouvèl sa yo ak klas, interfaces, Piki Depandans и CQRS dekri an detay nan liv mwen an "Achitekti aplikasyon entènèt konplèks". Genyen tou yon solisyon a devinèt poukisa tout klas mwen yo nan egzanp yo pou atik sa a yo make kòm final.

Sous: www.habr.com

Add nouvo kòmantè