vagrant
PHP7
homestead
TRPG
laravel5.5

クソゲーのキャラクターシート登録所みたいなものを作成する2

クソゲーのキャラクターシート登録所みたいなものを作成する - Qiita

おさらい

つらつらとゼロからサービス作成のログを取っています。
主に自分の理解度を確認のために。

そんなわけでクソゲーのキャラシー登録所を作成しています。

製造2

キャラクターの作成画面 その1

というわけで次は作成画面です。
たいていはゲーム中に眺めるキャラクターシートも兼ねています。

とりあえず画面遷移ができて、ダミーデータがなんとなく表示できて……というところを目指します。

ルーティング

web.php
Route::get('/actor/{id_rand}', 'CharacterController@show');
Route::get('/actor', 'CharacterController@show');

引数ありとなしの2パターンを記述します。
パラメータの渡し方がわからなかったんですが、指定した関数に自動で渡されるということでした。

コントローラー

前回作成したコントローラーに処理を追加します。

CharacterController.php
    /**
     * return Actor View with Actor Data.
     * If new Acter, then return Freshman.
     *
     * @param int $id
     * @return $this|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function show($id_rand = '')
    {
        $character = Character::where('id_rand', $id_rand)->first();

        return view('actor')->with([
            'character' => $character,
            'ore' => $this->getOre($character),
        ]);
    }

    /**
     * Get 8 Data From Ore Table.
     * if Unset oreId, then return null.
     *
     * @param $character
     * @return array
     */
    private function getOre($character)
    {
        return null;
        return [
            Ore::where('id', $character->omote1_id)->first(),
            Ore::where('id', $character->omote2_id)->first(),
            Ore::where('id', $character->omote3_id)->first(),
            Ore::where('id', $character->ura1_id)->first(),
            Ore::where('id', $character->ura2_id)->first(),
            Ore::where('id', $character->ura3_id)->first(),
            Ore::where('id', $character->ura4_id)->first(),
            Ore::where('id', $character->ura5_id)->first(),
        ];
    }

関数showでactorビューをreturnします。
ついでに、withでキャラクターのデータを渡しています。
Ores(俺表)については、getOreがすごいことになってますが、とりあえず後回しです。

Charactersのデータですが、貰った引数に該当するデータがないとか、そもそも引数がない場合は単純にnullが渡されます。

※なお、後ほどreturn nullを消すどころじゃなく再修正します……。

ビュー

適当に格納できる画面を作成します。

actor.blade.php(超抜粋)
            <div class="col-md-2">プレイヤー名</div>
            <div class="col-md-6"><input type="text" name="player_name" value="{{ old('player_name', null_escape($character->player_name)) }}"></div>

null_escapeはSQLで言うところのcoallese的なヘルパー関数になります。

ヘルパー関数

app/helpers.php
<?php

if (! function_exists('null_escape'))
{
    /**
     * いわゆるisnullやcoallese
     *
     * @param $v
     * @param $d
     * @return mixed
     */
    function null_escape($v, $d = '') { return empty($v) ? $d : $v; }
}

nullなら基本的に空文字を返し、第2引数を指定していればそれを返す関数です。

型?
なにそれ美味しいの?

一旦動きを確認

してみます。

トップページのリンクから遷移。

スクリーンショット 2018-05-10 12.51.33.jpg

おお、できてる。
URLもhttp://moumienai.test/actor/jh4azBGSEqqZhUojEs1xとかになってます。
いい感じです。
やる気出てきました。

レイアウトがえらいことになってるのは見なかったことにしてます。

キャラクターの作成画面 その2

さて、では参照する俺表のデータを格納するOresテーブルを作成して、更に読み出すようにしてやります。

DB

マイグレーション

php artisan make:migration CreateOresTable
create_ores_table.php
    public function up()
    {
        Schema::create('ores', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('ore_id');
            $table->string('text1');
            $table->string('text2')->nullable();
            $table->tinyInteger('good')->default(0);
            $table->tinyInteger('evil')->default(0);
            $table->tinyInteger('social')->default(0);
            $table->timestamps();
        });
    }

up()を修正します。

基本的にデータを取得するときはore_idを利用することになります。

text1とtext2は、自由入力欄対策となります。
text2がnullの場合は自由入力欄がない項目ということです。

ダミーデータの修正

CharactersのダミーデータでOresのデータを表示させたいので、値が入るように修正します。

CharactersTableSeeder.php(追加)
                'omote1_id' => $faker->numberBetween(1, 100),
                'omote2_id' => $faker->numberBetween(1, 100),
                'omote3_id' => $faker->numberBetween(1, 100),
                'ura1_id' => $faker->numberBetween(1, 100),
                'ura2_id' => $faker->numberBetween(1, 100),
                'ura3_id' => $faker->numberBetween(1, 100),
                'ura4_id' => $faker->numberBetween(1, 100),
                'ura5_id' => $faker->numberBetween(1, 100),

1~100なのはなんとなく表示されない場合がある方が面白いかなと思ったからです。
実際には、テーブルに存在しないidが格納されることはないはずですが……。

というか、OresのデータもSeederで作成するようにしないと面倒ですね。
どうせどこかで作成する必要がありますし……。

php artisan make:seeder OresTableSeeder
OresTableSeeder
    public function run()
    {
        $faker = Faker\Factory::create('ja_JP');

        for ($i = 1; $i <= 50; $i++)
        {
            DB::table('ores')->insert([
                'ore_id' => $i,
                'text1' => $faker->text(),
                'text2' => $faker->randomElement([null, $faker->text()]),
                'good' => $faker->numberBetween(1, 5) - 3,
                'evil' => $faker->numberBetween(1, 5) - 3,
                'social' => $faker->numberBetween(1, 5) - 3,
                'created_at' => $faker->dateTime(),
                'updated_at' => $faker->dateTime(),
            ]);
        }
    }

といいつつダミーデータでお茶を濁します。

DatabaseSeeder.php(修正)
    public function run()
    {
        $this->call([
//            UsersTableSeeder::class,
            CharactersTableSeeder::class,
            OresTableSeeder::class,
        ]);
    }

DatabaseSeeder.phpを修正して、php artisan migrate:refresh --seedでデータを作成し直します。

モデル

php artisan make:Model Ore

特にデータを渡したい・渡したくないはないので、fillableで全部渡してもいいんですけど面倒なのでスルーします。

コントローラー

先程修正したんですけどまた修正します。
新規作成のときに$characterがnullになるとどうあがいてもそのメンバーを参照しようとした時点でエラーになるんですね。
try~catchでも掴めないし参りました。

CharacterController.php
    /**
     * return Actor View with Actor Data.
     * If new Acter, then return Freshman.
     *
     * @param $id_rand
     * @return $this|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function show($id_rand = '')
    {
        $character = null_escape(Character::where('id_rand', $id_rand)->first(), new Character);

        return view('actor')->with([
            'character' => $character,
            'ore' => $this->getOre($character),
        ]);
    }

    /**
     * Get 8 Data From Ore Table.
     * if Unset oreId, then return null.
     *
     * @param $character
     * @return array
     */
    private function getOre($character)
    {
        return [
            null_escape(Ore::where('ore_id', $character->omote1_id)->first(), new Ore),
            null_escape(Ore::where('ore_id', $character->omote2_id)->first(), new Ore),
            null_escape(Ore::where('ore_id', $character->omote3_id)->first(), new Ore),
            null_escape(Ore::where('ore_id', $character->ura1_id)->first(), new Ore),
            null_escape(Ore::where('ore_id', $character->ura2_id)->first(), new Ore),
            null_escape(Ore::where('ore_id', $character->ura3_id)->first(), new Ore),
            null_escape(Ore::where('ore_id', $character->ura4_id)->first(), new Ore),
            null_escape(Ore::where('ore_id', $character->ura5_id)->first(), new Ore),
        ];
    }

\$characterと\$oreが本当にnullだと困るので、先ほど作成したヘルパー関数を利用して、nullの場合はnewしたモデルを渡してメンバーを参照できるようにしました。

それだけです。
ヘルパー関数作っておいてよかった……。

ビュー

表の顔・裏の顔の部分を、2つ目のパラメーター($ore)を参照するように修正します。
さらにtext2に値があればinputも表示させます。

actor.blade.php(表の顔・裏の顔)
    <div class="container">
        <div class="row">
            <div class="col-md-6 header">表の顔</div>
            <div class="col-md-6 header">裏の顔</div>
        </div>
        <div class="row">
            <div class="col-md-6">
                <p>{{ null_escape($ore[0]->text1, 'error') }}
                    @if (! empty($ore[0]->text2))
                    <input type="text" name="omote1_free" value="{{ old('omote1_free', null_escape($character->omote1_free)) }}">
                    @endif
                    {{ null_escape($ore[0]->text2) }}の、
                </p>
                <p>{{ null_escape($ore[1]->text1, 'error') }}
                    @if (! empty($ore[1]->text2))
                    <input type="text" name="omote2_free" value="{{ old('omote2_free', null_escape($character->omote2_free)) }}">
                    @endif
                    {{ null_escape($ore[1]->text2) }}で、
                </p>
                <p>{{ null_escape($ore[2]->text1, 'error') }}
                    @if (! empty($ore[2]->text2))
                        <input type="text" name="omote3_free" value="{{ old('omote3_free', null_escape($character->omote3_free)) }}">
                    @endif
                    {{ null_escape($ore[2]->text2) }}。
                </p>
            </div>
            <div class="col-md-6">
                <p>{{ null_escape($ore[3]->text1, 'error') }}
                    @if (! empty($ore[3]->text2))
                        <input type="text" name="ura1_free" value="{{ old('ura1_free', null_escape($character->ura1_free)) }}">
                    @endif
                    {{ null_escape($ore[3]->text2) }}の、
                </p>
                <p>{{ null_escape($ore[4]->text1, 'error') }}
                    @if (! empty($ore[4]->text2))
                        <input type="text" name="ura2_free" value="{{ old('ura2_free', null_escape($character->ura2_free)) }}">
                    @endif
                    {{ null_escape($ore[4]->text2) }}で、
                </p>
                <p>{{ null_escape($ore[5]->text1, 'error') }}
                    @if (! empty($ore[5]->text2))
                        <input type="text" name="ura3_free" value="{{ old('ura3_free', null_escape($character->ura3_free)) }}">
                    @endif
                    {{ null_escape($ore[5]->text2) }}し、
                </p>
                <p>{{ null_escape($ore[6]->text1, 'error') }}
                    @if (! empty($ore[6]->text2))
                        <input type="text" name="ura4_free" value="{{ old('ura4_free', null_escape($character->ura4_free)) }}">
                    @endif
                    {{ null_escape($ore[6]->text2) }}だし、
                </p>
                <p>{{ null_escape($ore[7]->text1, 'error') }}
                    @if (! empty($ore[7]->text2))
                        <input type="text" name="ura5_free" value="{{ old('ura5_free', null_escape($character->ura5_free)) }}">
                    @endif
                    {{ null_escape($ore[7]->text2) }}。
                </p>
            </div>
        </div>

ちょっと見苦しすぎるので、\$characterのこの関連の項目を配列に変えたい気分になっていますがとりあえずスルーします。

また、良心・邪心・社会信用度の初期値を表示するようにします。

actor.blade.php(冒頭)
@php
$good = 12;
$evil = 12;
$social = 17;
foreach ($ore as $item)
{
    $good += $item->good;
    $evil += $item->evil;
    $social += $item->social;
}
@endphp

俺表の結果でそれぞれの値が増減するので、合算します。

actor.blade.php(良心・邪心・社会信用度)
    <div class="container">
        <div class="row">
            <div class="col-md-2">良心</div>
            <div class="col-md-2">
                <select name="good">
                    @for ($i = 0; $i <= 24; $i++)
                        <option value="{{ $i }}" @if ($i == null_escape($character->good, $good)) selected @endif>{{ $i }}</option>
                    @endfor
                </select>
                (初期 {{ $good }})
            </div>
            <div class="col-md-2">邪心</div>
            <div class="col-md-2">
                <select name="good">
                    @for ($i = 0; $i <= 24; $i++)
                        <option value="{{ $i }}" @if ($i == null_escape($character->evil, $evil)) selected @endif>{{ $i }}</option>
                    @endfor
                </select>
                (初期 {{ $evil }})
            </div>
            <div class="col-md-2">社会信用度</div>
            <div class="col-md-2">
                <select name="good">
                    @for ($i = 0; $i <= 33; $i++)
                        <option value="{{ $i }}" @if ($i == null_escape($character->social, $social)) selected @endif>{{ $i }}</option>
                    @endfor
                </select>
                (初期 {{ $social }})
            </div>
        </div>
        <div class="row">
            <div class="col-md-2">最も大切な人(物)</div>
            <div class="col-md-10"><input type="text" name="most_important" value="{{ old('most_important', null_escape($character->most_important)) }}"></div>
        </div>
    </div>

適当に初期値を表示してみます。

再度動きを確認

こんな感じになりました。

スクリーンショット 2018-05-10 22.11.12.jpg

狙い通り、初期値としてそれっぽい値が表示されてます。
あと、inputが表示されたりされなかったりしてます。

いい感じです。