socialgekon.com
  • Главни
  • Животни Циклус Производа
  • Мобиле
  • Остало
  • Уи Десигн
Технологија

Одржавајте танке ПХП МВЦ оквире слојевитом структуром

Масни контролери и модели: неизбежни проблем за већину великих пројеката заснованих на МВЦ оквирима као што су Иии и Ларавел. Примарна ствар која тови контролере и моделе је Ацтиве Рецорд , моћна и суштинска компонента таквих оквира.

Проблем: Активни записи и кршење СРП-а

Активни запис је архитектонски образац, приступ приступу подацима у бази података. Назвао га је Мартин Фовлер у својој књизи из 2003. године Обрасци архитектуре пословних апликација и широко се користи у ПХП Оквири.

Упркос чињеници да је то веома потребан приступ, образац активне евиденције (АР) крши принцип јединствене одговорности (СРП) јер модели АР:



  • Бавите се упитима и уштедом података.
  • Знајте превише о осталим моделима у систему (кроз везе).
  • Често су директно укључени у пословну логику апликације (јер је примена складиштења података уско повезана са поменутом пословном логиком).

Ово кршење СРП-а представља добру замену за брзи развој када треба што пре створити прототип апликације, али је прилично штетно када апликација прерасте у средњи или велики пројекат. „Божје“ моделе и масне контролере је тешко тестирати и одржавати, а слободно коришћење модела свуда у контролерима доводи до огромних потешкоћа када неизбежно морате променити структуру базе података.

Решење је једноставно: поделите одговорност Ацтиве Рецорд-а на неколико слојева и убризгајте зависне слојеве. Овај приступ ће такође поједноставити тестирање јер вам омогућава да се ругате оним слојевима који се тренутно не тестирају.

Решење: Слојевита структура за ПХП МВЦ оквире

„Дебела“ ПХП МВЦ апликација има зависности свуда, међусобно се блокира и склона је грешкама, док слојевита структура користи ињекцију зависности како би ствари биле чисте и јасне.

Пет основних слојева ћемо обрадити:

  • Тхе слој контролера
  • Тхе сервисни слој
  • ДТО , подскуп сервисног слоја
  • Погледајте декоратере , подскуп сервисног слоја
  • Тхе слој спремишта

Слојевита ПХП структура

Да бисмо применили слојевиту структуру, потребан нам је контејнер за убризгавање зависности , објекат који зна како да инстанцира и конфигурише објекте. Не треба да креирате класу јер оквир управља са свом чаролијом. Узмите у обзир следеће:

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

У горњем примеру, UserService се убризгава у SiteController, UserRepository се убризгава у UserService и АР модели User и Logs се убризгавају у UserRepository класа. Овај код контејнера је прилично једноставан, па разговарајмо о слојевима.

Слој контролера

Савремени МВЦ оквири попут Ларавел и Иии преузимају многе традиционалне изазове за вас: Провера ваљаности уноса и предфилтери се премештају у други део апликације (у Ларавелу је то што се зове миддлеваре док се у Иии то зове понашање ) док се рутирањем и ХТТП глаголским правилима рукује у оквиру. Ово оставља врло уску функционалност програмеру да кодира у контролер.

Суштина контролера је добијање захтева и достављање резултата. Контролер не би требало да садржи било какву пословну логику; у супротном је тешко поново користити код или променити начин на који апликација комуницира. Ако, на пример, требате да креирате АПИ уместо приказивања приказа, а ваш контролер не садржи никакву логику, само промените начин на који враћате податке и спремни сте.

Овај танки слој контролера често збуњује програмере, а будући да је контролер задани слој и највиша улазна тачка, многи програмери само додају нови код својим контролерима без икаквог додатног размишљања о архитектури. Као резултат, прекомерне одговорности се додају, одговорности попут:

  • Пословна логика (што онемогућава поновну употребу кода пословне логике).
  • Директне промене стања модела (у том случају би све промене у бази података довеле до огромних промена свуда у коду).
  • Логика релације модела (као што су сложени упити, спајање више модела; опет, ако се нешто промени у бази података или у релацији логика, морали бисмо то променити у свим контролерима).

Размотримо пример преинжењерираног контролера:

//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')); }

Зашто је овај пример лош? Из бројних разлога:

  • Садржи превише пословне логике.
  • Директно ради са активним записом, па ако промените нешто у бази података, на пример, преименујте last_login поље, морате га променити у свим контролерима.
  • Зна за релације база података, па ако се нешто промени у бази података, морамо то променити свуда.
  • Није за поновну употребу, што доводи до понављања кода.

Контролер треба да буде танак; заиста, све што треба да уради је да узме захтев и врати резултате. Ево доброг примера:

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

Али где нестају све те друге ствари? Припада сервисни слој .

Сервисни ниво

Сервисни слој је слој пословне логике. Овде и само овде треба да буду смештене информације о току пословних процеса и интеракцији између пословних модела. Ово је апстрактни слој и он ће се разликовати за сваку апликацију, али општи принцип је неовисност од вашег извора података (одговорност контролора) и складиштења података (одговорност доњег слоја).

Ово је фаза са највише потенцијала за проблеме раста. Често се модел активног записа враћа у контролер, и као резултат тога, приказ (или у случају АПИ одговора контролер) мора да ради са моделом и да буде свестан његових атрибута и зависности. То ствари чини неуредним; ако одлучите да промените релацију или атрибут модела активног записа, морате је променити свуда у свим својим приказима и контролерима.

Ево уобичајеног примера модела Ацтиве Рецорд који се користи у приказу:

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

Изгледа директно, али ако преименујем first_name поље, одједном морам да променим све приказе који користе поље овог модела, процес подложан грешкама. Најлакши начин да се избегне ова загонетка је коришћење објеката за пренос података или ДТО-а.

Објекти за пренос података

Податке из сервисног слоја треба умотати у једноставан непроменљиви објекат - што значи да се не могу променити након што се креира - тако да нам за ДТО нису потребни никакви постављачи. Даље, класа ДТО треба да буде независна и да не проширује ниједан модел Ацтиве Рецорд. Ипак, опрезно - пословни модел није увек исти као АР модел.

Размотрите захтев за доставу намирница. Логично, поруџбина у продавници мора да садржи информације о испоруци, али у бази података складиштимо поруџбине и повезујемо их са корисником, а корисник је повезан са адресом за испоруку. У овом случају постоји више АР модела, али горњи слојеви не би требало да знају за њих. Наша ДТО класа ће садржати не само поруџбину већ и информације о испоруци и било које друге делове који су у складу са пословним моделом. Ако променимо АР моделе повезане са овим пословним моделом (на пример, податке о испоруци преместимо у табелу поруџбина), променићемо само мапирање поља у ДТО објекту, уместо да променимо вашу употребу поља АР модела свуда у коду.

Користећи ДТО приступ, уклањамо искушење да променимо модел активног записа у контролеру или у приказу. Друго, ДТО приступ решава проблем повезаности између физичког складиштења података и логичког представљања апстрактног пословног модела. Ако нешто треба променити на нивоу базе података, промене ће утицати на ДТО објекат, а не на контролере и погледе. Видите образац?

Погледајмо једноставан ДТО:

//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}; } }

Коришћење нашег новог ДТО-а је једнако једноставно:

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

Погледајте декоратере

За раздвајање логике приказа (попут избора боје дугмета на основу неког статуса) има смисла користити додатни слој декоратора. А. декоратер је дизајнерски образац који омогућава украшавање основног објекта омотавањем прилагођеним методама. Обично се то дешава у погледу са помало посебном логиком.

Иако ДТО објекат може да обавља посао декоратора, он заиста функционише само за уобичајене радње попут форматирања датума. ДТО треба да представља пословни модел, док декоратер украшава податке ХТМЛ-ом за одређене странице.

Погледајмо фрагмент иконе статуса корисничког профила који не користи декоратера:

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

Иако је овај пример једноставан, програмеру би било лако да се изгуби у сложенијој логици. Овде долази декоратор, како би се очистила читљивост ХТМЛ-а. Проширимо исечак иконе статуса у целу класу декоратора:

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

Коришћење декоратера је једноставно:

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

Сада у приказу можемо користити атрибуте модела без икаквих услова и логике, и много је читљивији:

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

Декоратори се такође могу комбиновати:

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

Сваки декоратер ће радити свој посао и украшавати само свој део. Ово рекурзивно уграђивање неколико декоратера омогућава динамичну комбинацију њихових карактеристика без увођења додатних класа.

Слој спремишта

Слој спремишта ради са конкретном имплементацијом складиштења података. Најбоље је убризгати спремиште кроз интерфејс ради флексибилности и једноставне замене. Ако промените складиште података, морате да направите ново спремиште које имплементира интерфејс спремишта, али бар не морате да мењате остале слојеве.

Спремиште игра улогу објекта упита: добија податке из базе података и спроводи рад неколико модела активних записа. У овом контексту модели активних записа играју улогу појединачних ентитета модела података - било који објекат у систему за који желите да моделирате и чувате информације. Иако сваки ентитет садржи информације, он не зна како су се појавили (да ли су створени или добијени из базе података) или како да сачува и промени сопствено стање. Одговорност спремишта је да сачува и / или ажурира ентитет; ово обезбеђује боље раздвајање забринутости задржавањем управљања ентитетима у спремишту и поједностављивањем ентитета.

Ево директног примера методе спремишта која гради упит користећи знање о бази података и односима активног записа:

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

Одржавање виткости са слојевима с једном одговорношћу

У новоствореној апликацији наћи ћете само директоријуме за контролере, моделе и погледе. Ни Иии ни Ларавел не додају додатне слојеве у структуру своје примере апликације. Лака и интуитивна, чак и за почетнике, МВЦ структура поједностављује рад са оквиром, али важно је схватити да је њихов пример примера пример; то није стандард или стил и не намеће никаква правила о архитектури апликације. Подјелом задатака у одвојене слојеве са једном одговорношћу добијамо флексибилну и прошириву архитектуру која се лако одржава. Запамтити:

  • Ентитети су појединачни модели података.
  • Репозиторијуми дохватити и припремити податке.
  • Тхе сервисни слој има само пословну логику.
  • Контролери комуницирајте са свим спољним изворима попут корисничког уноса или независне услуге.

Дакле, ако започнете сложени пројекат или пројекат који има шансе да расте у будућности, размислите о јасној подели одговорности на слојеве контролера, услуге и спремишта.

Како направити фото колаж на иПхоне-у: апликације и идеје

Уређивање

Како направити фото колаж на иПхоне-у: апликације и идеје
Супер једноставан водич за иконографију

Супер једноставан водич за иконографију

Уи Десигн

Популар Постс
Зашто размотрити редизајн веб странице - савети и препоруке
Зашто размотрити редизајн веб странице - савети и препоруке
Шта вреди стартуп? Смернице и најбоље праксе
Шта вреди стартуп? Смернице и најбоље праксе
Развој паметних сатова: да ли паметни сатови вреде проблема?
Развој паметних сатова: да ли паметни сатови вреде проблема?
Да ли су сви трендови вредни тога? 5 најчешћих УКС грешака које дизајнери праве
Да ли су сви трендови вредни тога? 5 најчешћих УКС грешака које дизајнери праве
Како уређивати ИоуТубе видео записе на иПхоне-у помоћу ИоуТубе уређивача
Како уређивати ИоуТубе видео записе на иПхоне-у помоћу ИоуТубе уређивача
 
Соул хиперцикл и талас нових фитнес бутика
Соул хиперцикл и талас нових фитнес бутика
Стратегије одређивања цена за успех: Практични водич
Стратегије одређивања цена за успех: Практични водич
Изазов Интернет цензура: Како сам направио веб локацију за прикупљање проверених микроблога
Изазов Интернет цензура: Како сам направио веб локацију за прикупљање проверених микроблога
Аутоматски поставите веб апликације користећи ГитХуб Вебхоокс
Аутоматски поставите веб апликације користећи ГитХуб Вебхоокс
Водич за стримовање Апацхе Спарк-а: Идентификовање хасхтагова у тренду са Твиттера
Водич за стримовање Апацхе Спарк-а: Идентификовање хасхтагова у тренду са Твиттера
Категорије
Рисе Оф РемотеПрофитабилност И ЕфикасностНаука О Подацима И Базе ПодатакаИнтернет Фронт-ЕндДизајн БрендаПројектни МенаџментЉуди И ТимовиТрендовиЖивот ДизајнераБудућност Посла

© 2023 | Сва Права Задржана

socialgekon.com