Проверка модели Laravel: как разрешить только ОДНУ связанную модель - PullRequest
1 голос
/ 09 октября 2019

У меня есть модель Training с записью

enter image description here

В моей модели Observation я должен отметить обратную связь с обучением,

Желаемое поведение - разрешить только одно наблюдение за тренировку. Например, если у меня есть 3 тренинга, я могу ввести 3 наблюдения. Моя проблема в том, что мой код позволяет мне добавлять несколько наблюдений для каждого тренинга. Я хотел бы лучше справиться с этим с сообщением об ошибке.

enter image description here

Вот идея моего кода на данный момент

public function store(Request $request)
{
  $request->validate([
    'instruction' => 'required',
    'description' => 'required',
    'fk_student' => 'required'
  ]);

  $instruction = $request->get('instruction'); 
  $description = $request->get('description');
  $fk_student = $request->get('fk_student');

  $trainings = Training::where('fk_student', $request->get('fk_student'))->first();

  if(!isset($trainings)){ 
    return redirect()->route('observations.index')
                     ->with('error', 'No training, no observation! ');
  } else {
    Observation::create($request->all());
    return redirect()->route('observations.index')
                     ->with('success', 'Add');
  }
}

Ответы [ 2 ]

1 голос
/ 11 октября 2019

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


Метод 1:Фронтенд

Лично я считаю, что это лучшее решение. Его проще всего реализовать, и он дает желаемый результат. Все, что вам нужно сделать, это отключить кнопку «Добавить», если Training уже имеет Observation записано:

your-view.blade.php:

<h1>Listing Observations</h1>

<!-- Observations Table -->

<button{{ $training->observations()->exists() ? ' disabled' : '' }}>Add</button>

Этого будет достаточно для 99,999% всех пользователей этого приложения. Конечно, опытный пользователь все еще может отправить запрос, несмотря на то, что кнопка отключена. По моему (циничному) мнению, я не собираюсь «элегантно проваливаться» для пользователя, который пытается обойти систему.

Но это зависит от вас. Вы можете просто реализовать этот метод и назвать его хорошим. Если вы решили, что хотите, чтобы система была более устойчивой, вы можете реализовать метод 2 или метод 3.

ПРИМЕЧАНИЕ : По моему мнению, если вы решите реализовать метод 2или 3, , вы все равно должны реализовать метод 1 . Его очень просто реализовать, и он обеспечивает гораздо более приятный UX, чем позволить пользователю заполнить форму Observation, а затем сказать им, что ему разрешено создать только один Observation.


.

Метод 2: Backend - Eloquent

Eloquent позволяет запросить наличие связанной модели. Это означает, что вы можете проверить, есть ли у Training соответствующий Observation, прежде чем создавать его.

public function store(Request $request)
{
  $request->validate([
    'instruction' => 'required',
    'description' => 'required',
    'fk_student' => 'required'
  ]);

  $instruction = $request->get('instruction'); 
  $description = $request->get('description');
  $fk_student = $request->get('fk_student');

  $trainings = Training::where('fk_student', $request->get('fk_student'))->first();

  if(!isset($trainings)){ 
    return redirect()->route('observations.index')
                     ->with('error', 'No training, no observation! ');
  }

  if ($trainings->observations()->exists()) {
    /******************************************************************************
     * I'm returning a plain text response. Depending on your front end code, it
     * might make more sense to return a JSON response. Whatever response type you
     * choose, make sure that you respond with an HTTP error code. I think
     * 400 – Bad Request makes the most sense).
     ******************************************************************************
     */
    return response('An Observation already exists for this Training', 400)
           ->header('Content-Type', 'text/plain');
  }

  // If we make it to this point, it is safe to go ahead and create the Observation
  Observation::create($request->all());

  return redirect()->route('observations.index')
                   ->with('success', 'Add');
}

Метод 3: Серверная часть - База данных

Наконец, вы можете позволить базе данных обработать это для вас. Идея этого метода заключается в том, что вы создаете ограничение базы данных, ограничивающее число Observations на Training одним. Имея это ограничение, вы обрабатываете отправку формы с предположением, что все идеально.

Однако, поскольку все не будет всегда идеально, вы должны окружить свой код блоком try/catch и обработать исключение, что база данных будетthrow.

/****************************************************************
 * You can add this to a new or an existing database migration.
 ****************************************************************
 */
public function up()
{
  Schema::table('observations', function($table) {
    $table->unsignedInteger('training_id')
          ->unique()
          ->nullable();
  });
}

YourController.php

public function store(Request $request)
{
  $request->validate([
    'instruction' => 'required',
    'description' => 'required',
    'fk_student' => 'required'
  ]);

  $instruction = $request->get('instruction'); 
  $description = $request->get('description');
  $fk_student = $request->get('fk_student');

  $trainings = Training::where('fk_student', $request->get('fk_student'))->first();

  if(!isset($trainings)){ 
    return redirect()->route('observations.index')
                     ->with('error', 'No training, no observation! ');
  }

  try {
    Observation::create($request->all());
    return redirect()->route('observations.index')
                     ->with('success', 'Add');
  } catch (\Exception $e) {
    /******************************************************************************
     * You shouldn't *really* return `$e->getMessage()` to the user. Just return
     * an error message that makes sense for the action the user attempted.
     ******************************************************************************
     */
    return response($e->getMessage(), 400)->header('Content-Type', 'text/plain');
  }
}
0 голосов
/ 10 октября 2019

делает уникальный внешний ключ для таблицы наблюдений:

$table->bigInteger('training_id')->unsigned()->unique();

и проверяет 'уникальность: наблюдения, training_id'

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