- 投稿日:2022-03-18T19:48:01+09:00
【Laravel】Web開発初心者が1週間で入門チュートリアルを実施した記録(5), (6)
以下の続き。 フォルダに続き、タスク一覧の作成もできた。 ■(4)の復習: ・外部キー制約の設定 // 外部キーを設定する $table->foreign('folder_id')->references('id')->on('folders'); ・Laravel が提供するクエリビルダの機能を使用したデータ操作 // 選ばれたフォルダに紐づくタスクを取得する $tasks = Task::where('folder_id', $current_folder->id)->get(); ・モデルクラスにおけるリレーションを意識した記載 上記はリレーションを意識してモデルクラスを記載することで以下のように表現できる。 $tasks = $current_folder->tasks()->get(); リレーションを意識したモデルクラスの記載 class Folder extends Model { public function tasks() { return $this->hasMany('App\Task'); } } ・アクセサ モデルクラスでgetStatusLabelAttribute()と定義した関数の戻り値を、コントローラーやテンプレートで以下のように取得できる。 <span class="label">{{ $task->status_label }}</span> ここまでが(4)の復習。 入門Laravelチュートリアル (5) ToDoアプリのフォルダ作成機能を作る 一覧画面を作成した後は、フォルダ作成機能をつくった。 開発の流れをおさらい。 ①ルーティング設定(web.php) ②コントローラーの作成・記載 ③マイグレーションファイルの作成・記載 ④マイグレーションの実行 ⑤モデルクラスの作成 ⑥テストデータの挿入 ⑦コントローラーの追記・修正 ⑧テンプレートの作成 ①ルーティング設定(web.php) Route::get('/folders/create', 'FolderController@showCreateForm')->name('folders.create'); Route::post('/folders/create', 'FolderController@create'); name メソッドによるルートの命名は get だけに定義しています。名前をつけてあとで呼び出せるのは URL だけなので、同じ URL で HTTP メソッド違いのルートがいくつかある場合はどれか一つに名前をつければ OK ※ getは一覧画面の「フォルダを追加」ボタンを押して、フォルダ追加画面に遷移してきた時。 postはフォルダ追加画面でフォルダ名を入力し「送信」ボタンを押した時。 まずはget時のshowCreateFormメソッドに関して実装していく。 ②コントローラーの作成・記載(showCreateForm) フォルダについての処理を受け持つ FolderController を作成。 ルーテイング設定時に記載した、showCreateFormとcreateメソッドを後ほど記載する。 まずは一覧画面からフォルダ追加画面に飛ばすshowCreateFormメソッドについて、テンプレート(view)に飛ばす処理を記載。 public function showCreateForm() { return view('folders/create'); } showCreateFormについては、③〜⑦は特にないため、⑧テンプレートの作成にうつる。 ⑧テンプレートの作成(showCreateForm) 「/resources/views/folders/create.blade.php」を作成して中身を書いていく。 フォルダ名を入れる入力フォームと「送信」ボタンがあるだけのシンプルな画面なので、基本的なHTML。 途中にある@csrfはCSRF トークンを含んだ input 要素を出力する。Web アプリケーションの脆弱性に対処するために用いられる文字列で、悪意のあるサイトからの POST リクエストを受け付けてしまうことを防ぐ。(この例だと、他のサイトから /folders/create に POST リクエストが送信されることを防ぐ。) Laravel では CSRF トークンのチェックは最初から組み込まれている。すべての POST リクエストに対して CSRF トークンが要求されるため、@csrf を書き忘れるとリクエスト送信時にエラーが発生する。 続いてput時のcreateメソッドに関して実装していく。 ②コントローラーの作成・記載(create) public function create(Request $request) { // フォルダモデルのインスタンスを作成する $folder = new Folder(); // タイトルに入力値を代入する $folder->title = $request->title; // インスタンスの状態をデータベースに書き込む $folder->save(); return redirect()->route('tasks.index', [ 'id' => $folder->id, ]); } フォルダ名を入力して「送信」ボタンを押した時の処理なので、新しいフォルダのタイトル(フォルダ名)をDBに保存して、view関数で一覧画面にリダイレクトしている。 なぜリダイレクトか? 画面遷移としては、一覧画面→フォルダ作成画面→一覧画面に戻るという流れになり、画面を作る必要はないので view メソッドは呼ばず、リダイレクトする。 ③〜⑦は特になく、リダイレクトするだけなので⑧テンプレートの作成もないため、一旦ここまでで単純なフォルダ作成まではできるようになっている。 以下で、入力値バリデーションを実装。 Laravel では FormRequest クラスがバリデーションを司ります。まずは artisan コマンドでクラスを作成します。 php artisan make:request CreateFolder →app/Http/Requests フォルダに CreateFolder.php が作成される。 この中のrule関数が重要。 public function rules() { return [ 'title' => 'required', // ★ ]; } 'title'はHTML 側での input 要素の name 属性に対応。必須入力を意味する required を指定しています。 テンプレートに、エラーメッセージを出力するための処理を実装する。 (5)の内容は以上。続いて(6)。 入門Laravelチュートリアル (6) ToDoアプリのタスク作成機能を作る (6)ではタスク作成機能を作った。 フォルダを作るかタスクを作るかの違いなので、基本的な流れは(5)と同様。 ①ルーティング設定 Route::get('/folders/{id}/tasks/create', 'TaskController@showCreateForm')->name('tasks.create'); Route::post('/folders/{id}/tasks/create', 'TaskController@create'); ※ getは一覧画面の「タスクを追加」ボタンを押して、タスク追加画面に遷移してきた時。 postはタスク追加画面でタイトルと期限を入力し「送信」ボタンを押した時。 まずはget時のshowCreateFormメソッドに関して実装していく。 ②コントローラーの作成・記載(showCreateForm) TaskControllerにshowCreateFormメソッドを追加。 public function showCreateForm(int $id) { return view('tasks/create', [ 'folder_id' => $id ]); } テンプレートで form 要素の action 属性としてタスク作成 URL(/folders/{id}/tasks/create)を作るためにフォルダの ID が必要なので、コントローラーメソッドの引数で受け取って view 関数でテンプレートに渡している。 showCreateFormについては、③〜⑦は特にないため、⑧テンプレートの作成にうつる。 ⑧テンプレートの作成(showCreateForm) 「/resources/views/tasks/create.blade.php」を作成して中身を書いていく。 タイトルと期限を入力し「送信」ボタンを押すだけなので基本的なHTML。 ただし、期限を入力する際にカレンダーから日付を選ぶようにしたいので「flatpickr」というJavascriptライブラリを使用する。 ・レイアウトの整理 ここで、フォルダとタスクのテンプレートで共通的に記載している箇所が多くあるので、レイアウトファイルを使用してコードをシンプルにする。 まずはレイアウト resources/views/layout.blade.php を作成。 レイアウトにはページごとに変わらない部分だけを記述。ページごとに変化する部分は @yield で穴埋めにする。 テンプレート「/resources/views/tasks/create.blade.php」の内容をレイアウトを読み込むかたちに修正。 @extends('layout')でレイアウトを読み込むことを宣言。 レイアウトで@yield('styles')などとしていた部分には、@section('styles')〜@endsectionなどで挟んだ内容が入る。 他のテンプレートについても同様に修正を加える。 フォルダ同様、バリデーションチェックを加えてshowCreateFormは終了。 続いてcreateですが、フォルダの時と同様、コントローラーにcreateメソッドを追加してテンプレートを修正するのみ。 ■バリデーションテスト 最後に期限日のバリデーションテストを実施。 開発用のデータベースとは別に、メモリ上の(つまりテストコードが実行し終わると消える)データベースを使う。これによりテストを実行する間だけ存在すればいいデータが開発の邪魔にならない。 config/database.php の connections に以下の設定を追加。 テストはsqliteで行う。 'connections' => [ // ★ この設定を追加 'sqlite_testing' => [ 'driver' => 'sqlite', 'database' => ':memory:', 'prefix' => '', ], // 中略 ] Laravel ではテスティングライブラリとして PHPUnit をサポートしている。設定ファイル phpunit.xml に DB_CONNECTION の設定を追加。 <php> <env name="APP_ENV" value="testing"/> <env name="DB_CONNECTION" value="sqlite_testing"/> <!-- ★ この行を追加--> <!-- 中略 --> </php> テストコードの雛形を生成 php artisan make:test TaskTest →tests/Feature/TaskTest.php が作成された。 テストコードを更新し、以下コマンドでテストを実施。 ./vendor/bin/phpunit ./tests/Feature/TaskTest.php --testdox 結果が緑のチェックマークが表示されれば OK 。 これにて(6)も完了
- 投稿日:2022-03-18T18:08:13+09:00
Webサイトのフッター下部の空白をなくすJavaScript関数&CSS(make footer stick at bottom)
下記の関数により、フッター下部の空白を埋めることができる。 どのページサイズ(縦)にも適応できる。 # JavaScript function makeFooterSticky(){ var footer_pos = $('.footer').offset().top; var footer_height = $('.footer').outerHeight(); var body_height = $(document.body).outerHeight(); if (footer_pos + footer_height < body_height){ $('.footer').addClass('fixed-bottom'); } else{ $('.footer').removeClass('fixed-bottom'); } } // CSS // bootstrapを使用している場合は、それに付属している。 .fixed-bottom { position: fixed; right: 0; bottom: 0; left: 0; z-index: 1030; } // .footerクラスはJqueryで識別するためだけに使用しているので、 // cssファイル内に記述する必要ない。 <!-- HTML --> <footer class="footer"> Fotterここ </footer> 使い方 Footerのエレメントにfooterクラスを追加する。 Bootstrapを使わない場合は、上記のCSSをcssファイルに追加する。 以下のJavaScriptをonloadなど必要なときに実行する。 makeFooterSticky();
- 投稿日:2022-03-18T17:22:15+09:00
Bootstrap5でCardsを利用して画像や文字を重ねる方法
はじめに 備忘録 Bootstrap5で画像や文字を重ねる方法の一例です。 こんな風にもできるんだなーくらいに思ってください。 誰かのお役に立てれば幸いです。 実装方法 Cardsの「card-img-overlay」を使います。 cardクラスの中身に「card-img-overlayのみ」を書くことによって背景に設定した色をそのまま表示することができます。 リファレンスには、 コンテンツは画像の高さを超えないようにしてください。もしコンテンツが画像より大きい場合、画像をはみだしてコンテンツが表示されます。 とあるので、これを逆手に取ります。 つまりcardクラスは使いますが、card-img-overlayがわざとcardの範囲をはみ出すようにすることで、自由にレイアウトができるようにしています。 また、cardクラスと一緒にborder-0クラスを指定することで、cardクラスに初期設定されている囲いの線を消すことができます。 <div class="card border-0"> <div class="card-img-overlay"> <div class="row"> <div class="col"> <p>card-img-overlayの中でrowを使うこともできるし</p> </div> <img src="foo.png" class="col" alt="foo"> </div> <div class="card-img-overlay"> <p>card-img-overlayをもう1回使うこともできる</p> <img src="hoge.png" class="" alt="hoge"> </div> </div> </div> この例では、重ねたい画像や文字の下にコンテンツが何もない状態を想定しています。 もし下にコンテンツを配置したい場合は、 初めのcard-img-overlayの中(<div class="row">や2つ目の<div class="card-img-overlay">と同じ階層)にHTMLを記述していく または 下に配置するコンテンツに、cardの大きさ分のmargin-topやpadding-topを設定する ことで解決できます。 参照
- 投稿日:2022-03-18T12:21:24+09:00
フロントエンドにおけるコンポーネントとは
TL;DR ついこの間。 ジュニアのマークアップエンジニアの話を聞いていて、 「意外とこの基準わかりづらいものなんだな」と思ったので、 ここ最近身につけた知識ベースで、直感的ではなくなるべく言語化する形で 「コンポーネントとはなんぞや」 「その粒度について」 示しておこうと思いました。 本題 コンポーネントとは コンポーネントとは、部品、成分、構成要素などの意味を持つ英単語。 ITの分野では機器やソフトウェア、システムの構成する部品や要素などのことを意味する。 ※コンポーネントとは - IT用語辞典 上記の通りコンポーネントとは、ある程度まとまったものを「部品として」分解したものになります。 さらにコンポーネントをその「部品」として分割する理由は以下になります。 コンポーネントがコンポーネントであるための前提として、「関心の分離」というものがあります。 厳密な定義で説明すると少し難しいのですが、噛み砕いていってしまえば、機能や振る舞いなどを明確に分離する、ということです。 ※Web製作者のためのCSS設計の教科書 p42 つまり、コンポーネントとは ・これはタイトルだよね ・これはリンク ・これはボタン ・これはタイトルと抜粋文とボタンがまとまったカード のように、その「関心・目的」に沿って分割したパーツの総称になります。 コンポーネントの粒度とは さて、上記のようにパーツごとにコンポーネントを分割するとして、 どのくらいの粒度で分割すべきなのかがわからない!ということが出てくるかと思います。 個人的には、Atomic Designの定義がこの「粒度の基準」としては、 かなり明確で、なおかつわかりやすいのではないかと思いました。 Atomic Designでは、以下のようにコンポーネントの粒度を定義しています。 粒度 定義 実際のパーツ Atoms 原子 ボタン、リンク、フォームパーツなど Molecules 分子 フォームパーツとボタンを組み合わせた検索フォームパーツ、ニュースリストの1行など、「動作・存在意図が明確」なパーツ Organisms 有機体 ブログのコンテンツなど、Molecules(動作)が複数まとまったことにより、ページ内のコンテンツの「ひとまとまり」となっているパーツ Templates ページ内のレイアウトテンプレート ヘッダー、フッター、左カラム、右カラムなど Pages ページ全体 ページ全体 特に、Atoms Designにおける「Atoms」「Molecules」の基準が、 MindBEMdingにおけるコンポーネント分割で重要な基準になります。 たとえば、以下の粒度のパーツは「Atoms」「Molecules」の粒度のコンポーネントとして成立します。 ボタンコンポーネントである c-btn (Atoms) ボタンの中にアイコンを表示させる c-icon (Atoms) 各段落のh要素である c-headingXX (Atoms) 「検索してください」という文言、input-text、「送信」ボタンをひとまとめにした c-search-form(Molecules) 日付、タイトル、カテゴリ、リンクをひとまとめにしたお知らせエリア内の1行 c-news-line (Molecules) 実際にAtomic Designのコンポーネント命名基準を利用するかは別として、 上記粒度でコンポーネントを区切り、CSSを分けることによって 汎用性の高いコンポーネント設計を作ることが できるのではないかと思います。 実際にコンポーネントを分割してみる コンポーネントを作成するにあたり、 上記の粒度で分割したコンポーネントはもちろん、 そのコンポーネントを「包括するパーツ」もコンポーネントとなり得ます。 たとえば、Qiitaのトップページは以下のような分割になり得ます。 (Atomsまで入れるとややこしくなるためAtomsは割愛します) ・・・とおもったけど、OrganismsとMoleculesが曖昧だなぁ・・・ このように、大きいコンポーネントの中に小さいコンポーネントを入れ子にして 一つ一つのコンポーネントを構成していきます。 1つのコンポーネントには孫要素くらい(できれば子要素)までのCSSを指定し、 それより内側の情報に関しては別コンポーネントとしてCSSを指定するようにします。 まとめ 上記の通り、コーディングする際のコンポーネント設計は 「小さいパーツをたくさん作る」 ↓ 「パーツを組み合わせる」 ↓ 「組み合わせたパーツを構造としてまとめる」 というボトムアップの考え方で実装していくとうまくいくかと思います。 今の私がそう言うのできているかは置いておいて 綺麗なマークアップやプログラミングができるようになると **後々の自分(これ重要)**やそのプロジェクトを引き継いだ人を助けることになります。 ・・・というわけでがんばりまっしょい!!!! 参考 本文に引用 Web製作者のためのCSS設計の教科書(情報古め) Atomic Design おすすめ Every Layout(ただしコンポーネント設計の説明はない気がする) ざっくりつかむ CSS設計 Kindle版(初心者向け)