Узнайте, как привести в порядок код, отделяя методы от контроллеров в других классах для повторного использования другими контроллерами. - PullRequest
0 голосов
/ 29 августа 2018

У меня такая ситуация, когда у меня есть CRUD в Laravel. Я занимаюсь опросом конкретных респондентов . План состоит в том, чтобы отправить им ссылку, содержащую случайно сгенерированную строку, то есть: https://larasurvey.app/survey/gewuygde7w6gded8ed7hw, где gewuygde7w6gded8ed7hw происходит из таблицы tokens.

Итак, моя Token.php модель выглядит следующим образом:

<?php

namespace App\Models\path;

use Illuminate\Database\Eloquent\Model;

class Token extends Model
{
    protected $table = 'tokens';
    protected $connection = 'external';

    /* RELATIONSHIPS */
    public function respondent(){
        return $this->belongsTo(Respondent::class,'respondent_id','id');
    }

    /* METHODS*/
    //Route Model Binding to get the token, instead of the default id, in the survey's URL
    public function getRouteKeyName()
    {
        return 'token';
    }

    /* ... */
}

Обратите внимание, что я использую привязку модели маршрута для получения токена вместо идентификатора.

Опрос состоит, скажем, из пяти разделов. В каждом разделе есть форма. В этой форме я использую Select2 , который является более динамичным полем выбора. Я использую несколько полей выбора, информация которых поступает из таблиц каталога.

Например, один каталог - это список университетов. Конечно, у нас нет всех университетов мира, поэтому я использую select2 с возможностью добавить новый университет, если его нет в каталоге университетов (таблица).

Вот код HTML ( blade ), который я использую для поля выбора университетов:

                {{-- University catalog --}}
                <div class="col-lg form-group" id="universities_row">
                    <label for="universities">University</label>
                    <select name="university" id="universities" class="form-control {{ $errors->has('university') ? 'is-invalid' : '' }}" aria-describedby="universityHelpBlock">
                        <option></option>
                        @foreach($universities as $key=>$university)
                            <option value="{{ $university->id }}" {{ old('university') == $university->id ? 'selected' : '' }}>{{ $university->name }}</option>
                        @endforeach
                    </select>
                    @if($errors->has('university'))
                        <div class="invalid-feedback">
                            {{ $errors->first('university') }}
                        </div>
                    @else
                        <small id="universityHelpBlock" class="form-text text-muted">Choose a university</small>
                    @endif
                </div>

А вот соответствующий javascript

$('#universities').select2({
                placeholder: "Type to search. If it doesn't exist, type the new one.",
                tags: true, /*Allows new value*/
                allowClear: true,
                width: '100%',/*Make it responsive*/
            });

Как вы знаете, теперь в контроллере , когда респондент выбирает университет, значение запроса $request->university является идентификатором. Однако, если пользователь вводит новое значение, Select2 возвращает текст.

Мне удалось сказать, когда значение $request->university является числом или когда это текст строки. Когда это не текст, я создал другой метод university_new($university) внутри контроллера, чтобы создать новую запись в каталоге universities (таблица) и вернуть новое сгенерированное значение идентификатора, чтобы сохранить его в * 1037. * колонка.

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

Вот (скажем) CoursesController.php :

<?php

namespace App\Http\Controllers\path\to\survey;

class CoursesController extends Controller
{
   public function store(Token $token, Request $request){
      //validation ...

      //call method to check if the university typed value is a new one or not:
      $university_id = university_new($request->university, $token);

      $course = new Course();
      $course->university_id = $university_id;
      // ... more columns
      $course->save();
   }
   // ...

   /*METHODS*/

        public function university_new($university,$token){
        //Checking whether ID has only numbers or not
        if(!ctype_digit($university)){
            //Check whether there is already one with that name
            $university_exists = University::where('name',$university)->first();
            if($university_exists){
                $university_id = $university_exists->id;
            }else{
                //create new University record:
                $universityNew = new University();
                $universityNew->name=$university;
                $universityNew->notes='Created by respondent: '.$token->respondent->id;
                $universityNew->created_ip=request()->ip();
                $universityNew->save();
                $university_id = $universityNew->id;
            }
        }else{
            //...
            $university_id = $university;
        }
        return $university_id;
    }
}

Пока все хорошо. Но функцию university_new() я хочу использовать в других контроллерах.

Я следовал этому учебному пособию , где объясняется, как этого добиться, сначала создав запрос проверки под названием CourseSaveRequest.php

<?php
//Validation when a new course data is saved

namespace App\Http\Requests\path\to\survey;

use App\Models\path\Token;
use Illuminate\Foundation\Http\FormRequest;

class CourseSaveRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        //Check the token
        $token = $this->route('token');
        /*if(Token::where('token',$token)->exists()){
            echo '<p>Found!</p>';
        }else{
            echo '<p>Not found</p>';
        }*/
        //dd($token);
        return Token::where('token',$token)->exists();
        //return false;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'myvalidationsRules'             =>  'required|alpha',
            //...
        ];
    }
}

, а затем я создал новый класс внутри каталога app/Service с именем universityCreateService.php, который выглядит следующим образом:

<?php

namespace App\Services\path\to\survey;

use App\Http\Requests\path\to\CourseSaveRequest;
use App\Models\path\to\University;
use App\Models\path\Token;

class universityCreateService
{
    public function university_new(CourseSaveRequest $request,Token $token){
        //Checking whether ID has only numbers or not
        if(!ctype_digit($request->university)){
            //Check whether there is already one with that name
            $university_exists = University::where('name',$request->university)->first();
            if($university_exists){
                $university_id = $university_exists->id;
            }else{
                //create new University record:
                $universityNew = new University();
                $universityNew->name=$request->university;
                $universityNew->notes='Created by respondent: '.$token->respondent->id;
                $universityNew->created_ip=request()->ip();
                $universityNew->save();
                $university_id = $universityNew->id;
            }
        }else{
            //...
            $university_id = $request->university;
        }
        return $university_id;
    }
}

Так что теперь внутри контроллера CoursesController.php Я вызываю класс, вводя его конструктором.

Изменено CoursesController.php

class CoursesController extends Controller
{
    private $universityCreateService;

    public function __construct(universityCreateService $createUniversity){
         $this->universityCreateService=$createUniversity;
    }

    public function store(Token $token, Request $request){
          //validation ...

          //call method to check if the university typed value is a new one or not:
          $university_id = $this->universityCreateService->university_new(); //calling the desired method, that is now in another class and injected in this controller.

          $course = new Course();
          $course->university_id = $university_id;
          // ... more columns
          $course->save();
       }
       // ...
}

Проблема сейчас в том, что когда я попадаю в секционные курсы (все, что связано с CoursesController.php), приложение laravel перенаправляет меня домой!

Почему это происходит?

Как мне это исправить?

Или есть другой подход к повторному использованию методов в нескольких контроллерах?

Как сделать метод, который изначально находится в контроллере, доступным для других контроллеров?

Обратите внимание, что я использую модель токена вместо логина.

В противном случае я могу расширить контроллер, , как описано здесь или показано в этом видеоуроке .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...