За последние 24 часа нас посетили 18045 программистов и 1609 роботов. Сейчас ищут 1360 программистов ...

Как разделить большой контроллер ?

Тема в разделе "Laravel", создана пользователем AlexPTZ, 18 сен 2019.

  1. AlexPTZ

    AlexPTZ Новичок

    С нами с:
    18 сен 2019
    Сообщения:
    8
    Симпатии:
    0
    Всем привет

    Разрабатываю админку для АТС. Дошел до "Настроек".
    Роуты API планируются следующие
    /api/pbx/trunks - внешние линии
    /api/pbx/dev - устройства
    /api/pbx/audio - голосовые файлы
    /api/pbx/ivr - голосовые меню
    ...ну и еще с десяток разделов

    создал модель и контроллер
    php artisan make:model PBX
    php artisan make:controller PBXController

    Подскажите пожалуйста - как "разбить" большой контроллер на мелкие ?
    Правильно-ли я мыслю, что надо в app/Http/Controllers создать папку PBX и в ней держать файлы
    TrunksController.php
    DevController.php
    AudioController.php
    IvrController.php
    ....

    Не могу понять - как их теперь правильно зацепить в имеющийся app/Http/Controllers/PBXController.php
     
  2. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям
    Тут нет единственно верного подхода. Что-то очень мало у тебя маршрутов и всего одна модель. :) А ты уже что-то разбивать собрался.

    В разбивке и группировке я бы танцевал от данных: прикинул какие таблицы нужны, разбил бы их на несколько групп по функциональной близости, как например так:

    Таблицы
    User, Department, Group, Role, Permission - это группа User
    Category, Board, Thread, Message - группа Communication и т.д.

    На каждую группу создал бы как минимум по сервису (или репозиторию) цель которого спрятать реализацию и предоставить методы кроме CRUD в едином стиле. Некоторые сервисы могут быть завязаны не на таблицы (не только на них), а на функционал или внешние API, например. Типа файловый сервис, который скрывает он контроллера, что работает с Amazon S3 для примера.

    К сервисам будут обращаться контроллеры, это новый уровень группировки. Скорее всего контроллеров будет меньше, чем сервисов и гораздо меньше, чем моделей.

    В общем случае логично в маршрутах использовать префиксы, соответствующие контроллерам или сервисам. Типа /api/reports/... /api/products/... Когда 99% работы происходит вне контроллера, он начинает состоять в основном из спецификаций apidoc и правил валидации.
     
  3. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Так можно. Но я обычно против кучи контроллеров, в каждом из которых по одной акции. Особенно, если учесть, что при правильном написании в методе контроллера должно быть от 1 до 10 строчек, если больше 10 строчек, уже надо выносить в сервис. ПОэтому 10 методов по 1-10 строчек - вполне себе читаемый контроллер получается.
     
  4. AlexPTZ

    AlexPTZ Новичок

    С нами с:
    18 сен 2019
    Сообщения:
    8
    Симпатии:
    0
    Каждый раздел в PBX от 200 строк
     
  5. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    метода в 200 строк вообще не должно быть в системе, ни одного. Если требуемое действие реализуется в 20 строк, оно должно быть разбито на мелкие методы, строк 20-30 от силы. иначе это читать невозможно, не говоря уж о тестировании или отладке
    ,
    Это у вас роут или префикс для группы роутов?
     
  6. AlexPTZ

    AlexPTZ Новичок

    С нами с:
    18 сен 2019
    Сообщения:
    8
    Симпатии:
    0
    200 строк - это весь блок, ответственный за функционал (и геттеры и сеттеры)
    Сейчас файл pbx.conf - почти 4000 строк. Вот и пытаюсь его раздробить на разделы

    /api/pbx - это префикс группы
     
  7. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    А я про 1-10 строк пишу - про нормальный размер одного метода контроллера, так что как одно с другим связано?
    А это что такое?
     
  8. AlexPTZ

    AlexPTZ Новичок

    С нами с:
    18 сен 2019
    Сообщения:
    8
    Симпатии:
    0
    ну какие-то есть короткие методы, какие-то длинные. Сейчас конечно буду другой уровень абстракции закладывать

    Это существующая админка. Переделываю ее
    --- Добавлено ---
    Я пока не силен в Laravel и к сожалению не вижу всех подводных камней в разработке на нем

    Попытаюсь сформулировать хотелки

    Задача № 1 - переписать существующее API, чтобы оно позволяло управлять данными

    /api/pbx - префикс группы настроек
    /api/pbx/trunk - управления транками
    /api/pbx/trunk.list - показать все транки
    /api/pbx/trunk.get - получить один
    /api/pbx/trunk.update - обновить
    /api/pbx/trunk.delete - удалить
    /api/pbx/trunk.insert - добавить
    /api/pbx/dev - управления устройствами
    /api/pbx/dev.list - показать все устройства
    /api/pbx/dev.get - получить один
    /api/pbx/dev.update - обновить
    /api/pbx/dev.delete - удалить
    /api/pbx/dev.insert - добавить
    При этом из метода /api/pbx/dev надо иметь доступ к api/pbx/trunk, чтобы например проверить корректность привязки устройства к внешней линии

    Задача № 2 - натянуть на новое API новую тему
     
  9. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Может сначала стоит выучить? А то я говорю конкретно - контроллер, а вы о чём-то ещё пишите. Я спрашиваю, это роут или группа, вы говорите роут, а оказывается группа.
    --- Добавлено ---
    Я когда начинаю с новым фреймворком или CMS или технологией разбираться, я сначала от корки до корки читаю документацию, а потом лезу что-то писать
     
  10. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям
    Это не очень хорошо. В REST принято действие (глагол) связывать с методом http, а не с адресом. То есть URL должен указывать на ресурс, например, Сообщение. Если по адресу обратиться методом POST это будет добавление, если PUT изменение, DELETE угадай что :)
    В Larsvel для упрощения работы с этим есть особый описатель маршрутов: redourse. Почитай об этом прежде чем делать.
    --- Добавлено ---
    Извини за рчепятки, я с мобилы пишу. Ломает исправлять.
     
    #10 artoodetoo, 18 сен 2019
    Последнее редактирование: 18 сен 2019
  11. AlexPTZ

    AlexPTZ Новичок

    С нами с:
    18 сен 2019
    Сообщения:
    8
    Симпатии:
    0
    ок. спасибо, опечатки не волнуют
     
  12. AlexPTZ

    AlexPTZ Новичок

    С нами с:
    18 сен 2019
    Сообщения:
    8
    Симпатии:
    0
    Правильно-ли я делаю или это говнокод, хотя и рабочий на данном этапе ?

    Создал провайдера и прописал его в config/app.php

    Файл app/Providers/MainServiceProvider.php
    Код (Text):
    1. <?php
    2.  
    3. namespace App\Providers;
    4.  
    5. use Illuminate\Support\ServiceProvider;
    6.  
    7. class MainProvider extends ServiceProvider
    8. {
    9.     /**
    10.      * Register services.
    11.      *
    12.      * @return void
    13.      */
    14.     public function register() // Импортируем функции из app/Services/*.php
    15.     {
    16.         foreach (glob(app_path('Services') . '/*.php') as $file) {
    17.             require_once $file;
    18.         }
    19.     }
    20.  
    21. }
    В app/Services два файла

    Файл app/Services/ServiceA.php
    Код (Text):
    1. <?php
    2.  
    3. namespace App\Providers\MainProvider\ServiceA;
    4.  
    5. function index() {
    6.     return [ "srvA #1","srvA #2", "srvA #3" ];
    7. }
    8.  
    9. function get( $id ) {
    10.     $items = index();
    11.     if ( $id<1 || $id > count( $items ) ) {
    12.         return false;
    13.     }
    14.     return ['id' => $id, 'name' => $items[ $id-1 ] ];
    15. }
    16.  
    17. ?>
    Файл app/Services/ServiceB.php
    Код (Text):
    1.  
    2. <?php
    3. namespace App\Providers\MainProvider\ServiceB;
    4.  
    5. use App\Providers\MainProvider\ServiceA as ServiceA;
    6. use Illuminate\Http\Request;
    7.  
    8. function index() {
    9.     return [ 'srvB #1', 'srvB #2', 'srvB #3'];
    10. }
    11.  
    12. function get( $id )
    13. {
    14.     $items = index();
    15.     if ( $id<1 || $id > count( $items ) ) {
    16.         return false;
    17.     }
    18.  
    19.     return [ 'id' => $id, 'name' => $items[ $id-1 ] ];
    20. }
    21.  
    22. function post( Request $request ) {
    23.     $id = $request->input('id');
    24.     $srvA_id = $request->input('srvA_Id');
    25.  
    26.     if ( !ServiceA\get( $srvA_id ) ) {
    27.         return [ 'id' => $id, 'srvA_Id' => $srvA_id, 'status' => 'Error - srvA not found' ];
    28.     }
    29.     return [ 'id' => $id, 'status' => 'Update ok' ];
    30. }
    31.  
    32. }
    33.  
    34. ?>
    Файл routes/api.php
    Код (Text):
    1.  
    2. <?php
    3. use Illuminate\Http\Request;
    4.  
    5. use App\Providers\MainProvider as MainProvider;
    6.  
    7.  
    8.     Route::get('srvA', function () {
    9.         $response = MainProvider\ServiceA\index();
    10.         return response( $response ,200);
    11.     });
    12.     Route::get('srvA/{id}', function ( $id ) {
    13.         $response = MainProvider\ServiceA\get( $id );
    14.         return response( $response ,200);
    15.     });
    16.  
    17.     Route::get('srvB', function () {
    18.         $response = MainProvider\ServiceB\index();
    19.         return response( $response ,200);
    20.     });
    21.     Route::get('srvB/{id}', function ( $id ) {
    22.         $response = MainProvider\ServiceB\get( $id );
    23.         return response( $response ,200);
    24.     });
    25.     Route::post('srvB', function ( Request $request ) {
    26.         $response = MainProvider\ServiceB\post( $request );
    27.         return response( $response ,200);
    28.     });
     
  13. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    Ну если у вас всё в таком роде, возьмите Slim какой-нибудь, вам ларавеля много. А так, вынесете в классы хотя бы ваши сервисы, чтоб автолоадинг находил.
     
  14. AlexPTZ

    AlexPTZ Новичок

    С нами с:
    18 сен 2019
    Сообщения:
    8
    Симпатии:
    0
    Пытался я вынести в классы - не получается :(
     
  15. AlexPTZ

    AlexPTZ Новичок

    С нами с:
    18 сен 2019
    Сообщения:
    8
    Симпатии:
    0
    Получилось вот так

    Создал провайдера и прописал его в config/app.php

    Файл app/Providers/MainServiceProvider.php
    Код (Text):
    1. <?php
    2.  
    3. namespace App\Providers;
    4.  
    5. use Illuminate\Support\ServiceProvider;
    6.  
    7. class MainProvider extends ServiceProvider
    8. {
    9. }
    В app/Services два файла

    Файл app/Services/ServiceA.php
    Код (Text):
    1. <?php
    2.  
    3. namespace App\Providers\MainProvider;
    4.  
    5. class ServiceA {
    6. public static function index() {
    7.     return [ "srvA #1","srvA #2", "srvA #3" ];
    8. }
    9.  
    10. public static function get( $id ) {
    11.     $items = ServiceA::index();
    12.     if ( $id<1 || $id > count( $items ) ) {
    13.         return false;
    14.     }
    15.     return ['id' => $id, 'name' => $items[ $id-1 ] ];
    16. }
    17. }
    18. ?>
    Файл app/Services/ServiceB.php
    Код (Text):
    1.  
    2. <?php
    3. namespace App\Providers\MainProvider;
    4.  
    5. use App\Providers\MainProvider\ServiceA as ServiceA;
    6. use Illuminate\Http\Request;
    7.  
    8. class ServiceB {
    9. public static function index() {
    10.     return [ 'srvB #1', 'srvB #2', 'srvB #3'];
    11. }
    12.  
    13. public static function get( $id )
    14. {
    15.     $items = ServiceB::index();
    16.     if ( $id<1 || $id > count( $items ) ) {
    17.         return false;
    18.     }
    19.  
    20.     return [ 'id' => $id, 'name' => $items[ $id-1 ] ];
    21. }
    22.  
    23. public static function post( Request $request ) {
    24.     $id = $request->input('id');
    25.     $srvA_id = $request->input('srvA_Id');
    26.  
    27.     if ( !ServiceA::get( $srvA_id ) ) {
    28.         return [ 'id' => $id, 'srvA_Id' => $srvA_id, 'status' => 'Error - srvA not found' ];
    29.     }
    30.     return [ 'id' => $id, 'status' => 'Update ok' ];
    31. }
    32.  
    33. }
    34. }
    35. ?>
    Файл routes/api.php
    Код (Text):
    1.  
    2. <?php
    3. use Illuminate\Http\Request;
    4.  
    5. use App\Providers\MainProvider as MainProvider;
    6.  
    7.  
    8.     Route::get('srvA', function () {
    9.         $response = MainProvider\ServiceA::index();
    10.         return response( $response ,200);
    11.     });
    12.     Route::get('srvA/{id}', function ( $id ) {
    13.         $response = MainProvider\ServiceA::get( $id );
    14.         return response( $response ,200);
    15.     });
    16.  
    17.     Route::get('srvB', function () {
    18.         $response = MainProvider\ServiceB::index();
    19.         return response( $response ,200);
    20.     });
    21.     Route::get('srvB/{id}', function ( $id ) {
    22.         $response = MainProvider\ServiceB::get( $id );
    23.         return response( $response ,200);
    24.     });
    25.     Route::post('srvB', function ( Request $request ) {
    26.         $response = MainProvider\ServiceB::post( $request );
    27.         return response( $response ,200);
    28.     });
     
  16. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям