socialgekon.com
  • Tärkein
  • Suunnitteluprosessi
  • Muokkaus
  • Prosessi Ja Työkalut
  • Sijoittajat Ja Rahoitus
Teknologia

Ylläpidä ohut PHP MVC -rakenne, jossa on kerrostettu rakenne

Rasvan säätimet ja mallit: väistämätön ongelma useimmille MVC-kehyksiin perustuville suurille projekteille, kuten Yii ja Laravel. Tärkein asia, joka lihottaa ohjaimia ja malleja, on Aktiivinen ennätys , voimakas ja olennainen osa tällaisia ​​kehyksiä.

Ongelma: Aktiiviset tietueet ja sen rikkominen SRP: ssä

Aktiivinen tietue on arkkitehtoninen malli, lähestymistapa tietojen käyttämiseen tietokannassa. Sen nimitti Martin Fowler kirjassaan 2003 Yrityssovellusarkkitehtuurin mallit ja sitä käytetään laajalti PHP Kehykset.

Huolimatta siitä, että se on erittäin välttämätön lähestymistapa, Active Record (AR) -malli rikkoo yhden vastuun periaatetta (SRP), koska AR-mallit:

  • Käsittele kyselyjä ja tietojen tallentamista.
  • Tiedä liikaa järjestelmän muista malleista (suhteiden kautta).
  • Ovat usein suoraan mukana sovelluksen liiketoimintalogiikassa (koska tietojen tallennuksen toteutus liittyy läheisesti mainittuun liiketoimintalogiikkaan).

Tämä SRP-rikkomus on hyvä kompromissi nopealle kehitykselle, kun sinun on luotava sovelluksen prototyyppi mahdollisimman pian, mutta se on melko haitallista, kun sovelluksesta kasvaa keski- tai laajamittainen projekti. ”Jumala” -malleja ja rasvan säätimiä on vaikea testata ja ylläpitää, ja mallien vapaa käyttö kaikkialla ohjaimissa johtaa valtaviin vaikeuksiin, kun tietokannan rakennetta on väistämättä muutettava.

Ratkaisu on yksinkertainen: jaa aktiivisen tietueen vastuu useaan tasoon ja injektoi kerrosten välisiä riippuvuuksia. Tämä lähestymistapa yksinkertaistaa myös testausta, koska sen avulla voit pilkata niitä tasoja, joita ei tällä hetkellä testata.

Ratkaisu: PHP MVC -kehysten kerrostettu rakenne

'Rasvaisella' PHP MVC -sovelluksella on riippuvuuksia kaikkialla, lukitus ja altis virheille, kun taas kerrostettu rakenne käyttää riippuvuusinjektiota pitämään asiat puhtaina ja selkeinä.

Katamme viisi ensisijaista tasoa:

  • ohjainkerros
  • palvelutaso
  • DTO: t , palvelukerroksen osajoukko
  • Näytä sisustajat , palvelukerroksen osajoukko
  • arkistokerros

Kerroksinen PHP-rakenne

Kerroksisen rakenteen toteuttamiseksi tarvitsemme a riippuvuusinjektiosäiliö , objekti, joka osaa instantisoida ja konfiguroida objekteja. Sinun ei tarvitse luoda luokkaa, koska kehys hoitaa kaiken taikuuden. Harkitse seuraavaa:

class SiteController extends IlluminateRoutingController { protected $userService; public function __construct(UserService $userService) { $this->userService = $userService; } public function showUserProfile(Request $request) { $user = $this->userService->getUser($request->id); return view('user.profile', compact('user')); } } class UserService { protected $userRepository; public function __construct(UserRepository $userRepository) { $this->userRepository = $userRepository; } public function getUser($id) { $user = $this->userRepository->getUserById($id); $this->userRepository->logSession($user); return $user; } } class UserRepository { protected $userModel, $logModel; public function __construct(User $user, Log $log) { $this->userModel = $user; $this->logModel = $log; } public function getUserById($id) { return $this->userModel->findOrFail($id); } public function logSession($user) { $this->logModel->user = $user->id; $this->logModel->save(); } }

Yllä olevassa esimerkissä UserService ruiskutetaan SiteController, UserRepository ruiskutetaan UserService ja AR-mallit User ja Logs ruiskutetaan UserRepository luokassa. Tämä säilökoodi on melko yksinkertainen, joten puhutaan kerroksista.

Ohjaimen taso

Nykyaikaiset MVC-kehykset, kuten Laravel ja Yii, vastaavat moniin perinteisiin ohjainhaasteisiin: Syötön vahvistus ja esisuodattimet siirretään sovelluksen toiseen osaan (Laravelissa se on ns. väliohjelmisto kun taas Yii: ssä sitä kutsutaan käyttäytymistä ), kun taas reititys ja HTTP-verbisäännöt käsitellään kehyksessä. Tämä jättää ohjelmoijalle hyvin kapean toiminnallisuuden koodata ohjaimeksi.

Ohjaimen ydin on saada pyyntö ja toimittaa tulokset. Ohjain ei saa sisältää sovelluksen liiketoimintalogiikkaa; muuten on vaikea käyttää koodia uudelleen tai muuttaa sovelluksen viestintätapaa. Jos sinun on luotava sovellusliittymä esimerkiksi näkymien hahmontamisen sijaan eikä ohjaimesi sisällä mitään logiikkaa, muutat vain tietojen palautustapaa ja olet valmis lähtemään.

Tämä ohut ohjainkerros hämmentää usein ohjelmoijia, ja koska ohjain on oletuskerros ja ylimmän lähtökohdan, monet kehittäjät lisäävät vain uutta koodia ohjaimiinsa ajattelematta lisää arkkitehtuuria. Seurauksena on liiallinen vastuu, muun muassa:

  • Liikelogiikka (jonka vuoksi logiikkakoodin uudelleenkäyttö on mahdotonta).
  • Mallitilojen suorat muutokset (jolloin kaikki muutokset tietokantaan johtaisivat valtaviin muutoksiin kaikkialla koodissa).
  • Mallisuhdelogiikka (kuten monimutkaiset kyselyt, useiden mallien yhdistäminen; jälleen, jos jotain muutetaan tietokannassa tai relogiikassa, meidän on muutettava sitä kaikissa ohjaimissa).

Tarkastellaan esimerkiksi ylisuunniteltuja ohjaimia:

//A bad example of a controller public function user(Request $request) { $user = User::where('id', '=', $request->id) ->leftjoin('posts', function ($join) { $join->on('posts.user_id', '=', 'user.id') ->where('posts.status', '=', Post::STATUS_APPROVED); }) ->first(); if (!empty($user)) { $user->last_login = date('Y-m-d H:i:s'); } else { $user = new User(); $user->is_new = true; $user->save(); } return view('user.index', compact('user')); }

Miksi tämä esimerkki on huono? Monista syistä:

  • Se sisältää liikaa liiketoimintalogiikkaa.
  • Se toimii suoraan aktiivisen tietueen kanssa, joten jos muutat jotain tietokannasta, esimerkiksi nimeät last_login kentässä, sinun on vaihdettava se kaikissa ohjaimissa.
  • Se tietää tietokantasuhteista, joten jos jokin muuttuu tietokannassa, meidän on muutettava sitä kaikkialla.
  • Sitä ei voida käyttää uudelleen, mikä johtaa koodin toistamiseen.

Ohjaimen tulee olla ohut; oikeastaan ​​kaikki, mitä sen pitäisi tehdä, on ottaa pyyntö ja palauttaa tulokset. Tässä on hyvä esimerkki:

//A good example of a controller public function user (Request $request) { $user = $this->userService->getUserById($request->id); return view('user.index', compact('user')); }

Mutta mihin kaikki muut tavarat menevät? Se kuuluu palvelutaso .

Palvelukerros

Palvelutaso on liiketoimintalogiikan taso. Täällä ja vain täällä tulisi olla tietoa liiketoimintaprosessien kulusta ja liiketoimintamallien välisestä vuorovaikutuksesta. Tämä on abstrakti kerros ja se on erilainen kullekin sovellukselle, mutta yleinen periaate on riippumattomuus tietolähteestäsi (rekisterinpitäjän vastuu) ja tietojen tallennus (alemman kerroksen vastuu).

Tämä on vaihe, jolla on eniten potentiaalia kasvuongelmiin. Usein Active Record -malli palautetaan ohjaimelle, minkä seurauksena näkymän (tai API-vastauksen tapauksessa ohjaimen) on toimittava mallin kanssa ja oltava tietoinen sen ominaisuuksista ja riippuvuuksista. Tämä tekee asiat sotkuisiksi; Jos päätät muuttaa Active Record -mallin relaatiota tai määritettä, sinun on muutettava sitä kaikkialla kaikissa näkymissäsi ja ohjaimissasi.

Tässä on yleinen esimerkki näkymässä käytetystä Active Record -mallista:

    @foreach($user->posts as $post)
  • {{$post->title}}
  • @endforeach

Se näyttää suoraviivaiselta, mutta jos nimen uudelleen first_name minun on yhtäkkiä vaihdettava kaikkia näkymiä, jotka käyttävät tämän mallin kenttää, virhealtista prosessia. Helpoin tapa välttää tämä hämmennys on käyttää tiedonsiirtoobjekteja.

Tiedonsiirtokohteet

Palvelukerroksen tiedot on käärittävä yksinkertaiseksi muuttumattomaksi objektiksi - eli sitä ei voida muuttaa sen luomisen jälkeen -, joten DTO: lle ei tarvita asettimia. Lisäksi DTO-luokan tulisi olla riippumaton eikä laajentaa mitään Active Record -malleja. Varovainen - liiketoimintamalli ei kuitenkaan aina ole sama kuin AR-malli.

Harkitse päivittäistavarakaupan toimitussovellusta. Loogisesti, ruokakauppatilauksen on sisällettävä toimitustiedot, mutta tietokantaan tallennamme tilaukset ja linkitämme ne käyttäjään, ja käyttäjä on linkitetty toimitusosoitteeseen. Tässä tapauksessa on olemassa useita AR-malleja, mutta ylempien kerrosten ei pitäisi tietää niistä. DTO-luokkamme sisältää tilauksen lisäksi myös toimitustiedot ja muut liiketoimintamallin mukaiset osat. Jos muutamme tähän liiketoimintamalliin liittyviä AR-malleja (esimerkiksi siirrämme toimitustiedot tilaustaulukkoon), muutamme vain DTO-objektin kenttäkartoitusta sen sijaan, että muuttaisimme AR-mallikenttien käyttöä kaikkialla koodissa.

Käyttämällä DTO-lähestymistapaa poistamme houkutuksen muuttaa Active Record -mallia ohjaimessa tai näkymässä. Toiseksi DTO-lähestymistapa ratkaisee fyysisen datan tallennuksen ja abstraktin liiketoimintamallin loogisen esityksen välisen yhteyden ongelman. Jos jotain on muutettava tietokantatasolla, muutokset vaikuttavat DTO-objektiin eikä ohjaimiin ja näkymiin. Näetkö mallin?

Katsotaanpa yksinkertaista DTO: ta:

//Example of simple DTO class. You can add any logic of conversion from an Active Record object to business model here class DTO { private $entity; public static function make($model) { return new self($model); } public function __construct($model) { $this->entity = (object) $model->toArray(); } public function __get($name) { return $this->entity->{$name}; } }

Uuden DTO: n käyttäminen on yhtä suoraviivaista:

//usage example public function user (Request $request) { $user = $this->userService->getUserById($request->id); $user = DTO::make($user); return view('user.index', compact('user')); }

Näytä sisustajat

Näkymälogiikan erottamiseksi (kuten painikkeen värin valitseminen jonkin tilan perusteella) on järkevää käyttää ylimääräistä sisustajakerrosta. A sisustusarkkitehti on suunnittelumalli, joka sallii ydinobjektin koristamisen käärimällä sen mukautetuilla menetelmillä. Se tapahtuu yleensä näkymässä jonkin verran erityisellä logiikalla.

Vaikka DTO-objekti voi suorittaa sisustustyön, se toimii vain tavallisissa toiminnoissa, kuten päivämäärän muotoilu. DTO: n tulisi edustaa liiketoimintamallia, kun taas sisustaja kaunistaa tietoja HTML-koodilla tietyille sivuille.

Tarkastellaan katkelmaa käyttäjäprofiilin tilakuvakkeesta, joka ei käytä sisustajaa:

@if($user->status == AppModelsUser::STATUS_ONLINE) Online @else Offline @endif {{date('F j, Y', strtotime($user->lastOnline))}}

Vaikka tämä esimerkki on yksinkertainen, kehittäjän olisi helppo eksyä monimutkaisemmassa logiikassa. Tässä tulee sisään sisustaja, joka puhdistaa HTML-koodin luettavuuden. Laajennetaan tilakuvakkeen katkelma täydelliseen sisustajaluokkaan:

class UserProfileDecorator { private $entity; public static function decorate($model) { return new self($model); } public function __construct($model) { $this->entity = $model; } public function __get($name) { $methodName = 'get' . $name; if (method_exists(self::class, $methodName)) { return $this->$methodName(); } else { return $this->entity->{$name}; } } public function __call($name, $arguments) { return $this->entity->$name($arguments); } public function getStatus() { if($this->entity->status == AppModelsUser::STATUS_ONLINE) { return 'Online'; } else { return 'Offline'; } } public function getLastOnline() { return date('F j, Y', strtotime($this->entity->lastOnline)); } }

Sisustajan käyttö on helppoa:

public function user (Request $request) { $user = $this->userService->getUserById($request->id); $user = DTO::make($user); $user = UserProfileDecorator::decorate($user); return view('user.index', compact('user')); }

Nyt voimme käyttää mallin määritteitä näkymässä ilman ehtoja ja logiikkaa, ja se on paljon helpommin luettavissa:

{{$user->status}} {{$user->lastOnline}}

Sisustajia voidaan myös yhdistää:

public function user (Request $request) { $user = $this->userService->getUserById($request->id); $user = DTO::make($user); $user = UserDecorator::decorate($user); $user = UserProfileDecorator::decorate($user); return view('user.index', compact('user')); }

Jokainen sisustaja tekee työnsä ja koristaa vain oman osansa. Tämä useiden sisustajien rekursiivinen upottaminen mahdollistaa niiden ominaisuuksien dynaamisen yhdistämisen lisäämättä uusia luokkia.

Varastokerros

Varastokerros toimii tietotallennuksen konkreettisen toteutuksen kanssa. On parasta injektoida arkisto käyttöliittymän kautta joustavuutta ja helppoa vaihtamista varten. Jos muutat tietovarastoa, sinun on luotava uusi arkisto, joka toteuttaa tietokannan käyttöliittymän, mutta sinun ei ainakaan tarvitse muuttaa muita tasoja.

Tietovarasto on kyselyobjektin rooli: Se saa tietoja tietokannasta ja suorittaa useiden Active Record -mallien työn. Active Record -mallit näyttävät tässä yhteydessä yksittäisten tietomallien entiteettien - minkä tahansa järjestelmän järjestelmän objektin, josta haluat mallintaa ja tallentaa tietoja. Vaikka jokainen entiteetti sisältää tietoja, se ei tiedä miten se ilmestyi (jos se luotiin tai saatiin tietokannasta) tai kuinka tallentaa ja muuttaa omaa tilaansa. Tietovaraston vastuu on tallentaa ja / tai päivittää yksikkö; tämä erottaa huolenaiheet paremmin pitämällä entiteettien hallinnan arkistossa ja tekemällä yksiköistä yksinkertaisempia.

Tässä on yksinkertainen esimerkki arkistomenetelmästä, joka rakentaa kyselyn tietokannasta ja Active Record -suhteista saatujen tietojen avulla:

public function getUsers() { return User::leftjoin('posts', function ($join) { $join->on('posts.user_id', '=', 'user.id') ->where('posts.status', '=', Post::STATUS_APPROVED); }) ->leftjoin('orders', 'orders.user_id', '=', 'user.id') ->where('user.status', '=', User::STATUS_ACTIVE) ->where('orders.price', '>', 100) ->orderBy('orders.date') ->with('info') ->get(); }

Pitäminen ohuena yhden vastuun tasoilla

Äskettäin luotussa sovelluksessa on vain ohjaimia, malleja ja näkymiä koskevat kansiot. Yii ja Laravel eivät lisää ylimääräisiä tasoja esimerkkisovelluksen rakenteeseen. MVC: n rakenne on helppo ja intuitiivinen, myös aloittelijoille, yksinkertaistaa työskentelyä kehyksen kanssa, mutta on tärkeää ymmärtää, että heidän esimerkkisovelluksensa on esimerkki; se ei ole standardi tai tyyli, eikä se aseta mitään sääntöjä sovellusarkkitehtuurista. Jakamalla tehtävät erillisiin yksittäisiin vastuukerroksiin saamme joustavan ja laajennettavan arkkitehtuurin, jota on helppo ylläpitää. Muistaa:

  • Entiteetit ovat yksittäisiä tietomalleja.
  • Varastot noutaa ja valmistella tietoja.
  • palvelutaso on vain liiketoimintalogiikkaa.
  • Ohjaimet kommunikoida kaikkien ulkoisten lähteiden, kuten käyttäjän syötteen tai kolmannen osapuolen palvelun kanssa.

Joten jos aloitat monimutkaisen projektin tai projektin, jolla on mahdollisuus kasvaa tulevaisuudessa, harkitse selkeää vastuunjakoa ohjaimelle, palvelulle ja arkistokerroksille.

Estetiikka ja havainnointi - Kuinka lähestyä käyttökokemuksia

Ux-Suunnittelu

Estetiikka ja havainnointi - Kuinka lähestyä käyttökokemuksia
Tietorakenteen periaatteet mobiililaitteille (infografiikan kanssa)

Tietorakenteen periaatteet mobiililaitteille (infografiikan kanssa)

Ux-Suunnittelu

Suosittu Viestiä
Init.js: Opas Full-Stack-JavaScriptin miksi ja miten
Init.js: Opas Full-Stack-JavaScriptin miksi ja miten
Taso ylöspäin - opas pelin käyttöliittymään (infografiikan kanssa)
Taso ylöspäin - opas pelin käyttöliittymään (infografiikan kanssa)
Tarvitset sankarin: projektipäällikkö
Tarvitset sankarin: projektipäällikkö
Viimeinen opas päivämäärän ja ajan manipulointiin
Viimeinen opas päivämäärän ja ajan manipulointiin
Kuinka poseeraa kuvissa, jotta ne näyttävät rennolta ja luonnolliselta
Kuinka poseeraa kuvissa, jotta ne näyttävät rennolta ja luonnolliselta
 
Käytännöllinen lähestymistapa pelisuunnitteluun
Käytännöllinen lähestymistapa pelisuunnitteluun
Kuinka rakentaa vahva etätyökulttuuri: Haastattelu Christy Schumannin kanssa
Kuinka rakentaa vahva etätyökulttuuri: Haastattelu Christy Schumannin kanssa
Kannustaminen toimintaan ja oikea-aikaisuuteen etätyössä
Kannustaminen toimintaan ja oikea-aikaisuuteen etätyössä
Kuinka rekrytoida UX-tutkimuksen osallistujia
Kuinka rekrytoida UX-tutkimuksen osallistujia
Monimutkainen mutta kiinteä: Katsaus kiinteistöjen vesiputouksiin
Monimutkainen mutta kiinteä: Katsaus kiinteistöjen vesiputouksiin
Luokat
Tuotteen ElinkaariTeknologiaUi-SuunnitteluProsessi Ja TyökalutKaukosäätimen NousuiOS-vinkkejäSuunnitteluKetterä KykyOngelmien karttoittaminenSuunnittelu Ja Ennustaminen

© 2023 | Kaikki Oikeudet Pidätetään

socialgekon.com