【Laravel】newInstanceでプレビュー機能を作る

えび

例えば求人ポータルサイトなどで登録前に求人情報をプレビュー表示したい場合

・まだDBには入れてないけどリレーションをViewで使用したい
・実際の求人情報詳細画面と同じViewを使って共通化したい

そんな時に便利なのが newInstance()

早速実装してみる
今回はjobsテーブルという求人情報を入れるテーブルがある前提で進める

全部書くと大変などで所々端折ってます

プレビュー用のルーティング設定

  • routes/web.php
// 登録フォーム
Route::get('/jobs/create', 'JobController@create')->name('jobs.create');
// プレビュー処理
Route::post('/jobs/preview', 'JobController@preview')->name('jobs.preview');
// 登録処理
Route::post('/jobs', 'JobController@store')->name('jobs.store');

Controller作成

ここではメインとなる「求人作成フォームの表示」と「プレビュー処理」のみ記載
(実際には登録処理などのメソッドも必要)

  • JobController.php
<?php

namespace App\Http\Controllers;

use App\Models\Job;
use Illuminate\Http\Request;

class JobController extends Controller
{
    /**
     * 求人作成フォーム
     *
     * @return \Illuminate\Contracts\View\View
     */
    public function create()
    {
        return view('jobs.create');
    }

    /**
     * 求人プレビュー
     *
     * @param Request $request
     * @return \Illuminate\Contracts\View\View
     */
    public function preview(Request $request)
    {
        // viewに渡すjobインスタンスを作成
        $job = Job::make()->newInstance($request->input());
     
        return view('jobs.show', ['job' => $job, 'is_preview' => true]);
    }
}

実際に表示する求人詳細画面のViewと同じViewをプレビューでも使用しているのがポイント
共通化しているので区別するためにis_previewを渡してあげてる

また、newInstance()Non-static methodなのでJobがインスタンス化されていない場合はmake()関数をつけてあげる
もしコンストラクタでインスタンス化されている場合は下記でOK

$this->job->newInstance()

View作成

デザインやLayoutは省略で表示する部分だけざっくり書いてみる

  • jobs/create.blade.php
@section('content')
  <form method="post" action="{{ route('jobs.store') }}">
    @csrf
    <h1>求人作成</h1>

    <h2>タイトル</h2>
    <input type="text" name="title" value="{{ old('title') }}">

    <h2>求人内容</h2>
    <textarea name="content">{{ old('content') }}</textarea>

    <h2>会社</h2>
    <select name="company_id">
      <option value="1">会社1</option>
      <option value="2">会社2</option>
      <option value="3">会社3</option>
    </select>

    <button type="button" onclick="onClickPreview(this)">プレビューを見る</button>
    <button type="button" onclick="onClickSave(this)">保存する</button>
  </form>

  <script type="text/javascript">
       const onClickPreview = (button) => {
        button.form.action = '/jobs/preview'
        button.form.target = '_blank'
        button.form.submit()
      }

      const onClickSave = (button) => {
        button.form.action = '/jobs'
        button.form.target = '_self'
        button.form.submit()
      }
  </script>
@endsection

同じform内で「登録」か「プレビュー」かを切り分けるためJavaScriptを使用してる

  • jobs/show.blade.php
@section('content')
   @if (isset($is_preview))
     <p>※これはプレビュー表示です</p>
   @endif
   <h1>{{ $job->title }}</h1>
   <h2>求人内容</h2>
   <div>{!! nl2br(e($job->content)) !!}</div>
   <h2>求人を出している会社名</h2>
   <div>{{ $job->company->name }}</div>
@endsection

newInstanceリレーション (今回だとcompany_id) も指定してあげると、
$job->company->name のように従来のリレーションの呼び出しができるようになって便利

\ 案件のご依頼・ご相談はこちらから /