У меня такая ситуация, когда у меня есть 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 перенаправляет меня домой!
Почему это происходит?
Как мне это исправить?
Или есть другой подход к повторному использованию методов в нескольких контроллерах?
Как сделать метод, который изначально находится в контроллере, доступным для других контроллеров?
Обратите внимание, что я использую модель токена вместо логина.
В противном случае я могу расширить контроллер, , как описано здесь или показано в этом видеоуроке .