20210511のlaravelに関する記事は10件です。

laravel SQLSTATE[HY000] [1045] Access denied for user ‘root’@’localhost’ 解決メモ

キャッシュをクリアする php artisan cache:clear php artisan config:cache
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel6.x インストール方法

前提 composerはインストール済みであること。 composerとは,PHPアプリケーションのライブラリ、パッケージの依存関係を管理するツール。 composerインストール方法 1.composerを使用してLaravel6をインストールする。 composer create-project --prefer-dist laravel/laravel プロジェクト名 "6.*" crete-project --- composrでプロジェクトを作成 --prefer-dist --- リリース版、安定版をダウンロードする laravel/laravel --- ヘッダー名/パッケージ名 "6.x" --- バージョンの指定(指定していないと最新バージョンがインストールされる) 2..envの設定 DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=データベース名 DB_USERNAME=ユーザー名 DB_PASSWORD=パスワード 3./strageのパーミッションの変更 chmod 777 -R storage 4.bootstrap/cacheのパーミッションの設定 chmod -R 777 bootstrap/cache これでhttp://[IPアドレス]/[Laravelファイル名]/publicにアクセスするとLaravelのホーム画面が表示できるようになります!!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【コピペ】AWS Cloud9でLaravel環境を構築その壱

Macでも・・・Windowsでも・・・開発環境を構築できない場合、Cloud9しかないかなあ〜と思ったのでやってみました。 ミドルウェア達は手動で入れます。 マシンスペック Mac mini 2018 macOS Catalina(10.15.x) Intel Core-i7 3.2GHz 6コア メモリ 32GB SSD 512GB Laravel環境 Nginx 最新版 PHP(PHP-FPM) 7.2.x MySQL 5.7 Composer 最新版 Laravel 5.6 やること Cloud9でLaravel環境構築 ミドルウェア達は手動構築 AWS Cloud9の準備 下記を参考に準備する。 【コピペ】AWS Cloud9+Docker ComposeでLaravel環境を構築その壱#AWS Cloud9の準備 ミドルウェアなどの準備 PHPインストール PHPはインストール済み。 $ php -v PHP 7.2.24 (cli) (built: Oct 31 2019 18:27:08) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies でも、Laravelを動かすライブラリが不足してるので、インストールし直す。 $ sudo yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm $ sudo yum -y install --enablerepo=remi,remi-php72 php php-devel php-mbstring php-pdo php-gd php-xml php-pecl-mcrypt php-mysqlnd php-fpm php-pecl-zip php-bcmath ・・・ Complete! Nginxインストール $ sudo vi /etc/yum.repos.d/nginx.repo ★点線内をコピペ --- [nginx] name=nginx repo baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/ enabled=0 gpgcheck=0 --- :wq $ sudo yum -y --enablerepo=nginx install nginx 設定ファイルの編集 PHP-FPM /etc/php-fpm.d/www.conf $ sudo vi /etc/php-fpm.d/www.conf ★下記を点線内に編集 user = apache group = apache listen = /run/php-fpm/www.sock ;listen.owner = nobody ;listen.group = nobody ;listen.mode = 0660 ↓ --- user = nginx group = nginx listen = /var/run/php-fpm/php-fpm.sock listen.owner = nginx listen.group = nginx listen.mode = 0660 --- :wq Nginx /etc/nginx/conf.d/default.conf $ sudo vi /etc/nginx/conf.d/default.conf ★全行を削除 :%d ★点線内をコピペ --- server { listen 8080; server_name laravel.cloud9; charset UTF-8; access_log /var/log/nginx/access.log; location / { root /home/ec2-user/environment/laravel/public; try_files $uri /index.php?$query_string; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } location ~ \.php$ { root /home/ec2-user/environment/laravel/public; fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } --- :wq 起動および自動起動設定 $ sudo systemctl start php-fpm $ sudo systemctl enable php-fpm Created symlink from /etc/systemd/system/multi-user.target.wants/php-fpm.service to /usr/lib/systemd/system/php-fpm.service. $ sudo systemctl start nginx $ sudo systemctl enable nginx Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service. Nginxが/home/ec2-user配下を実行できるようにする $ chmod 701 /home/ec2-user MySQLインストール MariaDBのアンインストール $ rpm -qa | grep aria mariadb-common-10.2.36-1.amzn2.0.1.x86_64 mariadb-config-10.2.36-1.amzn2.0.1.x86_64 mariadb-libs-10.2.36-1.amzn2.0.1.x86_64 mariadb-10.2.36-1.amzn2.0.1.x86_64 $ sudo yum -y remove mariadb* $ sudo rm -rf /var/lib/mysql MySQLインストール $ sudo rpm -Uvh https://repo.mysql.com/yum/mysql-5.7-community/el/7/x86_64/mysql57-community-release-el7-10.noarch.rpm $ sudo yum -y install --enablerepo=mysql57-community mysql-community-server $ mysqld --version mysqld Ver 5.7.30 for Linux on x86_64 (MySQL Community Server (GPL)) $ sudo systemctl enable mysqld.service $ sudo systemctl start mysqld.service $ sudo grep 'temporary password' /var/log/mysqld.log 2020-06-14T11:56:34.296676Z 1 [Note] A temporary password is generated for root@localhost: XXXXXX $ sudo mysql_secure_installation Enter password for user root: XXXXXX ★パスワードは「英字小文字、英字大文字、数字、記号」の組み合わせにしたら通る 例)cloud9#CLOUD9 New password: cloud9#CLOUD9 Re-enter new password: cloud9#CLOUD9 〜 以降の質問は全て y で回答し、パスワード聞かれたら上記パスワードを入力する 〜 All done! データベース作成など $ mysql -u root -p Enter password: cloud9#CLOUD9 ★DB:hoge、USER:fuga、PASSWORD:cloud9#CLOUD9(※好きなのに変える) mysql> create database hoge default character set utf8 collate utf8_general_ci; mysql> CREATE USER fuga@'%' IDENTIFIED BY 'cloud9#CLOUD9'; mysql> GRANT ALL ON hoge.* TO fuga@'%'; mysql> CREATE USER fuga@'localhost' IDENTIFIED BY 'cloud9#CLOUD9'; mysql> GRANT ALL ON hoge.* TO fuga@'localhost'; mysql> FLUSH PRIVILEGES; mysql> quit Composerインストール $ curl https://getcomposer.org/installer | php $ sudo mv -i composer.phar /usr/local/bin/composer $ composer -v ______ / ____/___ ____ ___ ____ ____ ________ _____ / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/ / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/ /_/ Composer version 2.0.13 2021-04-27 13:11:08 ・・・ Laravelインストール プロジェクト作成 $ composer create-project --prefer-dist laravel/laravel laravel "5.6.*" パッケージ追加とパーミッション変更 $ cd laravel $ composer require --dev barryvdh/laravel-ide-helper $ composer require --dev squizlabs/php_codesniffer $ chmod -R 777 storage $ chmod -R 777 bootstrap/cache データベース接続設定 .env $ vi .env ★下記を点線内に編集 DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret ↓ --- DB_DATABASE=hoge DB_USERNAME=fuga DB_PASSWORD=cloud9#CLOUD9 --- :wq マイグレーション&シーダー実行 $ php artisan migrate:fresh --seed キャッシュとか色々クリアするシェル作成&実行 bin/clear-laravel.sh $ mkdir bin $ vi bin/clear-laravel.sh ★下記を点線内をコピペ --- #!/bin/bash php artisan view:clear php artisan cache:clear php artisan config:clear php artisan route:clear php artisan clear-compiled php artisan config:cache composer dump-autoload php artisan ide-helper:generate php artisan ide-helper:models -N php artisan ide-helper:meta --- :wq $ chmod 755 bin/clear-laravel.sh $ bin/clear-laravel.sh ブラウザで動作確認 「Preview」 → 「Preview Running Application」を選択する。 ブラウザを別タブで開く。 下記ページが表示されればOK。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】【備忘録】リソースコントローラーを使ってみよう

Laravelのリソースコントローラについてのメモです。 リソースコントローラーとは? データの追加、読み取り、更新、削除について決まりきった処理を簡潔にできる機能です。 使い方 以下のコマンドを実行します。 ターミナル php artisan make:controller ArticleController --resource 上記のArticleControllerは例ですので、任意で指定してあげてくださいね! 実行すると以下が作成されると思います。 app ┣ http ┣ Controllers ┣ ArticleController 中身を見てみましょう! ArticleController <?php namespace App\Http\Controllers; use App\Article; use Illuminate\Http\Request; class ArticleController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // } /** * Display the specified resource. * * @param \App\Article $article * @return \Illuminate\Http\Response */ public function show(Article $article) { // } /** * Show the form for editing the specified resource. * * @param \App\Article $article * @return \Illuminate\Http\Response */ public function edit(Article $article) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param \App\Article $article * @return \Illuminate\Http\Response */ public function update(Request $request, Article $article) { // } /** * Remove the specified resource from storage. * * @param \App\Article $article * @return \Illuminate\Http\Response */ public function destroy(Article $article) { // } } できました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel、Homesteadのデフォルトタイムゾーンを日本時間に設定する

開発環境構築時に気になったこと Homesteadを利用してLaravel環境を立ち上げていた時の話。 Laravelの立ち上げにコケてしまったので、エラーログを見てた時に気付いたのが、 2021/05/11 06:00:36 [error] 4599#4599: *1 FastCGI sent in stderr: "Unable to open primary script: /home/vagrant/code/public/index.php (No such file or directory)" ログを吐いてる時間がずれていた。アプリ側(config/app.php)はちゃんと設定しているはず。 $ php artisan tinker Psy Shell v0.10.8 (PHP 8.0.5 — cli) by Justin Hileman >>> echo Carbon\Carbon::now(); 2021-05-11 15:09:27 やはり時間がそろっていないと後々時間を扱うときに問題になりそう。ということでHomestead側でも日本時間を設定することに。 実行 $ sudo ln -sf /usr/share/zoneinfo/Japan /etc/localtime $ sudo ntpdate -v ntp.nict.jp 11 May 15:31:37 ntpdate[32548]: ntpdate 4.2.8p12@1.3728-o (1) 11 May 15:31:44 ntpdate[32548]: adjust time server 61.205.120.130 offset 0.027217 sec $ date Tue 11 May 2021 03:31:48 PM JST これでHomestead側でも日本時間を見てくれるようになった。 参考にさせていただいた記事 Laravel Homestead after.shを作成してHomestead.yamlと同じ階層においておけば、 vagrant upの際に日本時間に設定してくれるそうです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelのObserverについて

はじめに Observerではモデルのライフサイクル(create, updateなど)に合わせて設定した処理を行うようにすることができる。モデルをいじる時に毎回行う処理などを省略できるのでとても便利である。 ObserverファイルはLaravel 6.X以降であればphp artisan make:observer {Model名}Observer --model={Model名}で生成することができる({Model名}はモデルの名前で置き換えるという意味、Userモデルだったら{Model}=User)。それ以前のバージョンではApp\Observer配下に作成する。ファイル名は{Model名}Observer.phpと書く。 ReaDoubleでは、サービスプロバイダの一つであるbootメソッドで登録し、AppServiceProviderでオブザーバを登録しているが、この記事ではtraitを利用して登録する。traitとはコードを再利用するための仕組みの一つ。 オブザーバーの設定 オブザーバーは上記の方法で生成すると以下のような内容のファイルが生成される。そのままだが、createdメソッドには作られた後に行う処理を書く。updatedメソッドには更新した後に行う処理を書く。deletedメソッドには削除した後に行う処理を書く。restoredメソッドには再登録された後に行う処理を書く。forceDeletedメソッドには物理削除した後に行う処理を書く。 App\Observer\{Model名}Observer.php <?php namespace App\Observers; use App\Models\{Model名}; class {Model名}Observer { /** * Handle the {Model名} "created" event. * * @param \App\Models\{Model名} $model * @return void */ public function created({Model名} $model) { // } /** * Handle the User "updated" event. * * @param \App\Models\{Model名} $model * @return void */ public function updated({Model名} $model) { // } /** * Handle the User "deleted" event. * * @param \App\Models\{Model名} $model * @return void */ public function deleted({Model名} $model) { // } /** * Handle the User "restored" event. * * @param \App\Models\{Model名} $model * @return void */ public function restored({Model名} $model) { // } /** * Handle the User "force deleted" event. * * @param \App\Models\{Model名} $model * @return void */ public function forceDeleted({Model名} $model) { // } } あとは自分のしたい場所にしたい処理を書けば良い。デフォルトでは過去形のみが生成されるが、現在進行形(ing)の形でも動くようだ(処理前に呼び出される)。 オブザーバーの登録 まずはtraitに以下のように書く。bootクラス名はそのクラスが呼び出された時にそこに書かれた処理を行う。 App\Traits\{Model名}Observable.php <?php namespace App\Traits; trait {Model名}Observable.php { public static function boot{Model名}Observable() { self::observe({Model名}Observer::class); } } それを該当するModelsに呼び出す。 App\Models\{Model名} <?php namespace App\Models; use App\Traits\{Model名}Observable; use Illuminate\Database\Eloquent\Model; class {Model名} extends Model { use {Model名}Observable; } これをすることによって該当するモデルのEloquentが走ったときにboot{Model名}Observableメソッドを行うことが出来る。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravel fill() メソッドの定義場所 個人メモ

目的 各モデルクラスでモデルに配列を追加するときに使用するfill()メソッドの記載場所をメモ的にまとめておく 場所 アプリ名ディレクトリ/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.phpの中に記載されている。 下記に定義部分を抜粋して記載する。 アプリ名ディレクトリ/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php /** * Fill the model with an array of attributes. * * @param array $attributes * @return $this * * @throws \Illuminate\Database\Eloquent\MassAssignmentException */ public function fill(array $attributes) { $totallyGuarded = $this->totallyGuarded(); foreach ($this->fillableFromArray($attributes) as $key => $value) { $key = $this->removeTableFromKey($key); // The developers may choose to place some attributes in the "fillable" array // which means only those attributes may be set through mass assignment to // the model, and all others will just get ignored for security reasons. if ($this->isFillable($key)) { $this->setAttribute($key, $value); } elseif ($totallyGuarded) { throw new MassAssignmentException(sprintf( 'Add [%s] to fillable property to allow mass assignment on [%s].', $key, get_class($this) )); } } return $this; }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Cloud9でのLaravel環境構築に手こずっている人に捧ぐ

はじめに Cloud9の環境を立ち上げておいてください! 環境構築を完了させることに焦点を当てているため、コマンドの意味については細かく触れませんが、今後のためにわからない方はご自身で調べてみることをお勧めします! yumのアップデートを行う cloud9の画面に表示されているbash(ターミナル)を使っていきます。 まずcloud9のパッケージ管理ツールであるyumのアップデートから行いましょう。 下記のコマンドを実行します。 $ sudo yum -y update 最後の行に「Complete!」と表示されていれば大丈夫です。 AmazonLinuxにはPHPがデフォルトで入っているのですが、一応バージョンを確認しましょう。 PHPのバージョンを確認する $ php -v これでPHPのバージョンが表示されます。最新のものになっていたらいいのですが、古いバージョンの場合はアップデートしましょう。 ちなみに現時点の最新のものはPHP7系になりますが、僕の時は最新のものになってました。 バージョンアップが必要な方は以下のQiita記事などを参考にしてください。 https://qiita.com/kidatti/items/2d6a4a24f89dc71eb66e 必要なモジュールをインストールする PHPパッケージの中に必要なモジュールが入っているか確認しましょう。 以下のコマンドを実行します $ php -m モジュールのリストの中に、mbstring、pdo、mysqlndが入っていればOK,入っていないものがあればインストールしていきます。 例えば、mbstringが入ってなかった場合はまずは以下のようにコマンドで、インストールするモジュールの名前を一応確認しておきます。 $ sudo yum list | grep mbstring 次に、実行結果の中から「php-mbstring」の文字列をコピーして、下記のようにペーストして実行しましょう。 $ sudo yum -y install php-mbstring pdoやmysqlndがなかった方はmbstringの部分を書き換えればOKです。 Laravelのパッケージ管理ツールをインストールする コンポーザーというLaravelのパッケージ管理ツールをCloud9環境にインストールしていきます。 以下のコマンドを実行しましょう。 $ curl -sS https://getcomposer.org/installer | php これでコンポーザーの実行ファイルがインストールされているはずです。確認のため以下のコマンドを実行しましょう。 $ ls 「composer.phar」というファイルがあればちゃんとインストールされています。 次に、どこでも使えるようにするために、ローカルにファイルを移動させましょう。 以下のコマンドを実行します。 $ sudo mv composer.phar /usr/local/bin/composer では、コンポーザーを実行してみます。 $ composer これでコンポーザーがインストールされました。しかし、全てのファイルがインストールされていない可能性があるため、以下を実行してアップデートします。 $ composer update Laravelを起動する Laravelアプリを作成するために以下のコマンドを実行します。 「my-laravel」の部分はアプリ名のため、ご自身の好きなものに変更してOKです。 「"5.5.*"」の部分はLaravelのバージョンを示しているため、希望のバージョンに変更していただいてOKです。 $ composer create-project laravel/laravel my-laravel "5.5.*" --prefer-dist 作成が終わったら、以下のコマンドを実行してご自身のつけたアプリ名が表示されるか確認します。 $ ls しっかり入っていればOKです。では、ディレクトリを移動します。 ※ここでも「my-laravel」のところはご自身のアプリ名を入力します。 $ cd my-laravel ディレクトリの中身を確認してみましょう。 $ ls 「artisan」というのがあることを確認したら、次のコマンドを実行します。 $ php artisan key:generate そして、下記のコマンドを実行します。 $ php artisan serve --port=8080 これで、Cloud9のツールバーにある「Preview」から「Preview Running Application」でLaravelが起動できれば完了です。 お疲れ様でした!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel×Heroku】シンボリックリンクが上手くいかない時の対処法

"laravel シンボリックリンク" を検索すると、多くの関連記事が出てくると思います。 自分も、今回laravelアプリを開発していて、本番環境でシンボリックリンクが効いておらずハマったのですが、全く同じ境遇という方が見受けられなかったため、記事を書いています。 対象者 ・Laravelでstorageディレクトリを使った画像表示、ファイルの操作を行う方 前提 ・Laravelアプリを、Herokuにデプロイする方 ローカル環境でシンボリックリンクが上手くいっていない方は Laravelでpublicフォルダ配下に保存したファイルにアクセスできないを参考にしてみてください。 まずはこれを試してみる 今回の解決策を述べる前に、まずまだ何も試していない方は、以下を確認してみてください。 そもそも本番環境にシンボリックリンクが無い。 laravelで普通に開発をしている場合、ローカル環境で設定したシンボリックリンクはGitにpushされません。本番環境にGitと連携してpushする場合、Gitに無いものはpushされないのは当然のことです。 これを解消するには、アプリのホームディレクトリ上にある.gitignoreから、public/storageを削除してください。これで、ローカル環境で作成したシンボリックリンクはGitで管理されるようになるため、pushして、本番環境にデプロイしてみてください。 .gitignore /node_modules /public/hot /public/storage #削除 /storage/*.key /vendor .env .env.backup .phpunit.result.cache docker-compose.override.yml Homestead.json Homestead.yaml npm-debug.log yarn-error.log heroku run php artisan storage:linkを実行すれば良いんじゃないの? と思うかも知れません。自分もそう考えてHerokuにpushした後に実行してみましたが、効果はありませんでした。試しに、Herokuにssh接続してみた結果、シンボリックリンクが作成されて無いことに気が付きました。 さらに、ssh接続したHeroku上で、php artisan storage:linkを実行します。この瞬間では、public/storageとしてシンボリックリンクが作成されます。しかし、一度ssh接続を終了し、再度接続した時にはもう消えています。 Heroku上で直接行うのは意味がない Heroku上で、直接ファイル操作をするのは、意味がなかったようです。 Herokuはマルチテナントであるが故に、インスタンスの切り替えが発生するらしいです。 以下のタイミングでその切り替えが発生し、直接アップ(Git以外から操作)したファイルなどが消えてしまいます。 Git Push時 Heroku config変更時 おおむね1日1度、自動的に再起動 Heroku初心者がつまづいたこと3つ それでも動かない ・ローカル環境ではシンボリックリンクで正常に動作する ・本番環境では動作しないが、シンボリックリンクは存在する この2点が重なった場合、考えられる可能性は、以下の2つです。 ・権限の問題でアクセスできない ・シンボリックリンクのパスが環境の差異による影響を受けている 権限が無い場合 当方は、こちらに遭遇したことはないのですが、一応載せておきます。一応。 app/storageディレクトリのパーミッションの設定~Laravel初期設定~ シンボリックリンクのパスが環境の差異による影響を受けている 当方の場合、こちらでした。 Docker環境で開発しており、Herokuにはアプリ本体だけをデプロイしていたために発生しました。 ローカル環境のシンボリックリンクのパスを確認 % cd public % ls -l ...省略 lrwxr-xr-x ... storage -> /workspace/[アプリのディレクトリ]/storage/app/public ...省略 Herokuのシンボリックリンクのパスの確認 % heroku run bash [~ $ cd public [~/public $ ls -l lrwxrwxrwx ... dyno ... storage -> /workspace/[アプリのディレクトリ]/storage/app/public ローカル環境で作成したシンボリックリンクがそのままです。 しかし、Heroku環境はこのようなディレクトリ構造になっていないため、リンク切れになっていると想定できます。 Heroku上の正しいシンボリックリンクのリンクを確認 Herokuで正常に動作させるには、Heroku上のディレクトリ構造に合わせてあげなければなりません。 ただ、Heroku上で直接変更しても意味がないのは前述の通りです。 なので、Heroku上の正しいパスを確認し、それをローカル環境で設定し、pushし直します。 heroku [ ~ $ cd public [ ~/public $ rm storage [ ~/public $ ls -l #storageが無いことを確認してください。 [ ~/public $ cd [ ~ $ php artisan storage:link [ ~ $ cd public [ ~/public $ ls -l lrwxrwxrwx ... dyno ... storage -> /app/storage/app/public このように、Heroku上の正しいパスでシンボリックリンクが作成されます。 このパスで再設定してあげます。 ローカル % cd public % rm storage #既存のシンボリックリンクを削除します。 % ln -s /app/storage/app/public storage $ ln -s リンク元 登録名 リンク元に設定するリンク、登録名にシンボリックリンクの名前を設定します。 php artisan storage:linkはlaravelのコマンドですが、lnはlinuxコマンドです。 windowsの場合はmklinkコマンドがあります。 確認します。 % ls -l ... lrwxr-xr-x ... storage -> /app/storage/app/public ... これで、Heroku上のディレクトリ構造に合わせることができました。 ただし、ローカル環境で正常に動作しなくなるので、再設定が必要です。 再デプロイ 以上が設定し終わったら、Herokuにデプロイします。 正常に動作するはずです。 最後に 対処療法的なものだと思うので、もしよりベターな方法があればアドバイスいただけるとありがたいです。 参考にした記事 シンボリックリンクの作成, 確認, 削除 Laravel シンボリックリンクで少しハマった話 Heroku初心者がつまづいたこと3つ lnコマンドについて詳しくまとめました 【Linuxコマンド集】 app/storageディレクトリのパーミッションの設定~Laravel初期設定~ Laravelでpublicフォルダ配下に保存したファイルにアクセスできない Windows 10でシンボリックリンクを作成する Mklink - DOS コマンド一覧 herokuでアプリを指定してsshログイン 大変参考になりました。有難うございます!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでアプリを作ってみた!【Hanseee】

はじめに 私はプログラミング歴1年の初心者です。 実務でWebサイトのコーディングを1年間行ってきました。 そろそろシステム開発もできるようになりたいということで LaravelやReactをこれから勉強していこうと思っております。 今回の目的は ポートフォリオアプリを作成しようと思います。 Laravelの開発を1から行う gitをCLIで使えるようにする 開発環境は 今回はLaravel×PostgreSQL でいきます。 GUIツールはTablePlusを使ってみます。 ただし、postgresqlを使うことを途中で断念して mysqlに切り替えました。 設計 機能一覧 画面設計 URL設計 テーブル定義 前回と同様でスプレッドシートで作成してみました。 Laravelアプリ作成 $ laravel new Hanseee $ cd Hanseee PostgreSQLデータベース作成・設定 # postgreSQLのインストール $ brew search postgresql $ brew install postgresql $ postgres --version # postgreSQLのサーバー起動 $ pg_ctl -D /usr/local/var/postgres start # データベース一覧取得 $ psql -l # 環境変数へPATHを通す $ echo 'export PGDATA=/usr/local/var/postgres' >> ~/.zshrc $ source ~/.zshrc # ユーザーアカウントを追加 $ createuser -P [アカウント名] # データベースを作成 $ createdb [データベース名] -O [アカウント名]なので $ createdb Hanseee -O [アカウント名] $ psql -l ○TablePlasを使ってデータベースとつなげる 「Create new connection」をクリック DBを「PostgreSQL」をクリック Nameに「local」を指定 Userに「アカウント名」を指定 Databaseに「データベース名」を指定 ○.envの設定をする DB_CONNECTION=pgsql DB_HOST=127.0.0.1 DB_PORT=5432 DB_DATABASE=Hanseee DB_USERNAME=[アカウント名] DB_PASSWORD=[パスワード] ○PostgreSQLのドライバがないと怒られた $ php artisan migrate とすると could not find driver とかえってくる 調べましたがよくわからないので、諦めます! もし次回postgresqlを使うとなれば、Homesteadを使ってみようと思います。 mysqlの設定 // データベース作成 $ mysql -u root mysql> CREATE DATABASE `todoapp2`; mysql> SHOW databases; .envの設定は特になし database.php // mysqlのutfmb4をutf8に変更! 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', $ php artisan migrate GitHubに登録する この記事のGitHub登録でOKです。 マイグレーション作成 # マイグレーションファイルを作成 $ php artisan make:migration create_categories_table --create=categories $ problemのも $ stepのも xxxx_xx_xx_xxxxxx_create_categories_table.php // テーブル作成のために編集 Schema::create('categories', function (Blueprint $table) { $table->id(); $table->string('name', 20); $table->foreignId('user_id')->constrained(); $table->timestamps(); }); problemsのも stepsのも ユーザーログイン・新規登録機能 準備 # laravel/uiをインストール $ composer require laravel/ui $ php artisan ui vue --auth web.php // Routingを設定する Auth::routes(); Route::get('/', [App\Http\Controllers\HomeController::class, 'index'])->name('home'); resources/views/layout.blade.php // 共通テンプレートを作成する <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Kataduke</title> <link rel="stylesheet" href="/css/styles.css"> </head> <body> <header> <nav class="my-navbar"> <a class="my-navbar-brand" href="/">Hanseee</a> <div class="my-navbar-control"> @if(Auth::check()) <span class="my-navbar-item">こんにちは, {{ Auth::user()->name }}さん</span> | <a href="#" id="logout" class="my-navbar-item">ログアウト</a> <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;"> @csrf </form> @else <a class="my-navbar-item" href="{{ route('login') }}">ログイン</a> | <a class="my-navbar-item" href="{{ route('register') }}">会員登録</a> @endif </div> </nav> </header> <main> @yield('content') </main> @if(Auth::check()) <script> document.getElementById('logout').addEventListener('click', function(event) { event.preventDefault(); document.getElementById('logout-form').submit(); }); </script> @endif </body> </html> public/css/styles.css // cssファイルを作成する @import url('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'); @import url('https://cdnjs.cloudflare.com/ajax/libs/bootflat/2.0.4/css/bootflat.min.css'); body { background-color: #eee5d3; } .navbar { margin: 2rem 0 2.5rem 0; } .my-navbar { align-items: center; background: #709e6b; display: flex; height: 6rem; justify-content: space-between; padding: 0 2%; margin-bottom: 3rem; } .my-navbar-brand { font-size: 18px; } .my-navbar-brand, .my-navbar-item { color: #afc29f; } .my-navbar-brand:hover, a.my-navbar-item:hover { color: #fff; } .table tr td:first-child a { color: #333; font-weight: bold; } .table td:not(:first-child) { white-space: nowrap; width: 60px; } .table-room:hover, .table-room.act { background-color: #ddae87; } .form-control[disabled], .form-control[readonly] { background-color: #fff; } home.blade.php // テンプレートを設定する @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading"> ようこそ!まずはカテゴリを作成しましょう! </div> <div class="panel-body"> <div class="text-center"> <a href="#" class="btn btn-primary"> カテゴリ作成ページへ </a> </div> </div> </nav> </div> </div> </div> @endsection register.blade.php // テンプレートを設定する @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">会員登録</div> <div class="panel-body"> @if($errors->any()) <div class="alert alert-danger"> @foreach($errors->all() as $message) <p>{{ $message }}</p> @endforeach </div> @endif <form action="{{ route('register') }}" method="POST"> @csrf <div class="form-group"> <label for="email">メールアドレス</label> <input type="text" class="form-control" id="email" name="email" value="{{ old('email') }}" placeholder="(例) test@example.com" /> </div> <div class="form-group"> <label for="name">ユーザー名</label> <input type="text" class="form-control" id="name" name="name" value="{{ old('name') }}" placeholder="(例) 山田 太郎" /> </div> <div class="form-group"> <label for="password">パスワード</label> <input type="password" class="form-control" id="password" name="password" placeholder="パスワードは8文字以上"> </div> <div class="form-group"> <label for="password-confirm">パスワード(確認)</label> <input type="password" class="form-control" id="password-confirm" name="password_confirmation" placeholder="パスワードは8文字以上"> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">送信</button> </div> </form> </div> </nav> </div> </div> </div> @endsection login.blade.php // テンプレートを設定する @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">ログイン</div> <div class="panel-body"> @if($errors->any()) <div class="alert alert-danger"> @foreach($errors->all() as $message) <p>{{ $message }}</p> @endforeach </div> @endif <form action="{{ route('login') }}" method="POST"> @csrf <div class="form-group"> <label for="email">メールアドレス</label> <input type="text" class="form-control" id="email" name="email" value="{{ old('email') }}" /> </div> <div class="form-group"> <label for="password">パスワード</label> <input type="password" class="form-control" id="password" name="password" /> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">送信</button> </div> </form> </div> </nav> <div class="text-center"> <a href="{{ route('password.request') }}">パスワードの変更はこちらから</a> </div> </div> </div> </div> @endsection バリデーションの日本語化 RegisterController.php // リダイレクト先を変更 protected $redirectTo = '/'; // Validator::makeメソッドのattributesを設定 protected function validator(array $data) { return Validator::make($data, [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'string', 'email', 'max:255', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ], [], [ 'name' => 'ユーザー名', 'email' => 'メールアドレス', 'password' => 'パスワード', ]); } ログイン状態とログアウト状態の出し分け layout.blade.php // すでに実装済だが、以下の記述を追加する @if(Auth::check()) <span class="my-navbar-item">こんにちは, {{ Auth::user()->name }}さん</span> | <a href="#" id="logout" class="my-navbar-item">ログアウト</a> <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;"> @csrf </form> @else <a class="my-navbar-item" href="{{ route('login') }}">ログイン</a> | <a class="my-navbar-item" href="{{ route('register') }}">会員登録</a> @endif web.php // ログイン時のみのページにミドルウェアで認証 Route::group(['middleware' => 'auth'], function() { Route::get('/', [App\Http\Controllers\HomeController::class, 'index'])->name('home'); }) app/Http/Middleware/RedirectIfAuthenticated.php // ログイン状態時に、他の処理をせずにリダイレクトする // つまり、ログアウト時のみ他の処理をする設定 public function handle(Request $request, Closure $next, ...$guards) { $guards = empty($guards) ? [null] : $guards; foreach ($guards as $guard) { if (Auth::guard($guard)->check()) { return redirect('/'); } } return $next($request); } パスワード再設定 // .envでMailtrapに接続 MAIL_MAILER=smtp MAIL_HOST=smtp.mailtrap.io MAIL_PORT=2525 MAIL_USERNAME=ユーザー名 MAIL_PASSWORD=パスワード MAIL_ENCRYPTION= auth/passwords/email.blade.php @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">パスワード再発行</div> <div class="panel-body"> @if (session('status')) <div class="alert alert-success" role="alert"> {{ session('status') }} </div> @endif <form action="{{ route('password.email') }}" method="POST"> @csrf <div class="form-group"> <label for="email">メールアドレス</label> <input type="text" class="form-control" id="email" name="email" /> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">再発行リンクを送る</button> </div> </form> </div> </nav> </div> </div> </div> @endsection auth/passwords/reset.blade.php // input hiddenで$tokenをもたせる必要がある @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">パスワード再設定</div> <div class="panel-body"> <form action="{{ route('password.update') }}" method="POST"> @csrf <input type="hidden" name="token" value="{{ $token }}"> <div class="form-group"> <label for="email">メールアドレス</label> <input type="text" class="form-control" id="email" name="email" /> </div> <div class="form-group"> <label for="password">新しいパスワード</label> <input type="password" class="form-control" id="password" name="password" /> </div> <div class="form-group"> <label for="password-confirm">新しいパスワード(確認)</label> <input type="password" class="form-control" id="password-confirm" name="password_confirmation" /> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">再設定</button> </div> </form> </div> </nav> </div> </div> </div> @endsection Auth/ResetPasswordController.php // リダイレクト先を変更 protected $redirectTo = '/'; resources/views/mail/password-reset.blade.php // メールの内容テンプレートを編集 <a href="{{ route('password.reset', ['token' => $token]) }}"> パスワード再設定用リンク </a> App/Mail/ResetPassword.php // $ php artisan make:mail ResetPasswordをする // tokenに関する記述をする class ResetPassword extends Mailable { use Queueable, SerializesModels; public $token; /** * Create a new message instance. * * @return void */ public function __construct($token) { $this->token = $token; } /** * Build the message. * * @return $this */ public function build() { return $this->subject('パスワード再設定リンク')->view('mail.password-reset'); } } App/Models/User.php // 設定したパスワード再設定メールを送信する記述をする use App\Mail\ResetPassword; use Illuminate\Support\Facades\Mail; /** * パスワード再設定メールを送信する */ public function sendPasswordResetNotification($token) { Mail::to($this)->send(new ResetPassword($token)); } Category一覧機能 カテゴリ一覧表示機能 web.php // Routingの設定 Route::group(['middleware' => 'auth'], function() { Route::get('/categories', [App\Http\Controllers\CategoriesController::class, 'index'])->name('category.index'); }); Models/Category.php // Categoryモデル作成 $ php artisan make:model Category Models/User.php // CategoryとUserのリレーションをもたせる /** * ユーザーの設定したカテゴリを取得 */ public function categories() { return $this->hasMany(Category::class); } database/seeders/CategoriesTableSeeder.php // Categoryシーダー作成 $ php artisan make:seeder CategoriesTableSeeder use Carbon\Carbon; use Illuminate\Support\Facades\DB; public function run() { $names = ['仕事', '恋愛', '遊び', 'その他']; foreach($names as $name) { DB::table('categories')->insert([ 'name' => $name, 'user_id' => '2', 'created_at' => Carbon::now(), 'updated_at' => Carbon::now(), ]); } } CategoriesController.php // Categoryコントローラー作成 $ php artisan make:controller CategoriesController use Illuminate\Support\Facades\Auth; /** * ユーザーの持つカテゴリの一覧ページを表示する */ public function index() { $categories = Auth::user()->categories()->get(); return view('categories.index', [ 'categories' => $categories, ]); } resources/views/categories/index.blade.php // テンプレートを作成 @extends('layout') @section('content') <div class="container"> <ul class="nav justify-content-center"> @foreach($categories as $category) <li class="nav-item"> <a class="nav-link" href="#">{{ $category->name }}</a> </li> @endforeach <li class="nav-item"> <a class="nav-link btn btn-success" href="#">カテゴリ追加</a> </li> </ul> </div> @endsection views/layout.blade.php // bootstrap追加 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> ホーム画面からカテゴリ一覧ページへのリンク home.blade.php <a href="{{ route('categories.index') }}" class="btn btn-primary"> カテゴリ一覧ページへ </a> Category作成機能 カテゴリ作成ページ表示実装 web.php Route::group(['middleware' => 'auth'], function() { Route::get('/categories/create', [App\Http\Controllers\CategoriesController::class, 'create'])->name('categories.create'); Route::post('/categories', [App\Http\Controllers\CategoriesController::class, 'store']); }); CategoriesController.php // カテゴリ作成ページ表示 public function create() { return view('categories.create'); } views/categories/create.blade.php // カテゴリ作成ページのテンプレート作成 @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">ルームを登録する</div> <div class="panel-body"> @if($errors->any()) <div class="alert alert-danger"> <ul> @foreach($errors->all() as $message) <li>{{ $message }}</li> @endforeach </ul> </div> @endif <form action="{{ route('categories.store') }}" method="post"> @csrf <div class="form-group"> <label for="name">カテゴリ名</label> <input type="text" class="form-control" name="name" id="name" value="{{ old('name') }}" /> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">追加</button> </div> </form> </div> </nav> </div> </div> </div> @endsection カテゴリ保存機能実装 CategoriesController.php // カテゴリ保存機能 use App\Models\Category; use App\Http\Requests\CreateCategory; public function store(CreateCategory $request) { $category = new Category(); $category->name = $request->name; Auth::user()->categories()->save($category); return redirect()->route('categories.index'); } Requests/CreateCategory.php // Requestsクラス作成 $ php artisan make:request CreateCategory public function authorize() { return true; } public function rules() { return [ 'name' => 'requiredmax:20', ]; } エラーメッセージの日本語化 /resources/lang/ja/validation.php // 日本語化用のファイルを作成 $ mkdir resources/lang/ja $ cp ./resources/lang/en/validation.php ./resources/lang/ja 'required' => ':attribute は入力必須です。', 'max'の'string' => ':attribute は :max 文字以内で入力してください。', Requests/CreateCategory.php /** * エラーメッセージを日本語化 * * @return array */ public function attributes() { return [ 'name' => 'カテゴリ名', ]; } config/app.php 'locale' => 'ja', カテゴリ一覧画面からカテゴリ作成画面へのリンク views/categories/index.blade.php <a class="nav-link btn btn-success" href="{{ route('categories.create') }}">カテゴリ追加</a> Problem一覧機能 課題一覧表示機能の実装 web.php // Routingの設定 Route::get('/categories/{category}/problems', [App\Http\Controllers\ProblemsController::class, 'index'])->name('problems.index'); Models/Problem.php // モデル作成 $ php artisan make:model Problem Models/Category.php // カテゴリと課題とのリレーション /** * カテゴリが持つ課題を取得 */ public function problems() { return $this->hasMany(Problem::class); } datebase/seeds/ProblemsTableSeeder.php // シーダー作成 $ php artisan make:seeder ProblemsTableSeeder use Carbon\Carbon; use Illuminate\Support\Facades\DB; public function run() { $titles = ['タイトル1', 'タイトル2', 'タイトル3']; foreach($titles as $title) { DB::table('problems')->insert([ 'title' => $title, 'category_id' => 1, 'created_at' =>Carbon::now(), 'updated_at' =>Carbon::now(), ]); } } // シード実装 $ php artisan db:seed --class=ProblemsTableSeeder ProblemsController.php // コントローラー作成 $ php artisan make:controller ProblemsController use Illuminate\Support\Facades\Auth; use App\Models\Category; public function index(Category $category) { $categories = Auth::user()->categories()->get(); $problems = $category->problems()->get(); return view('problems.index', [ 'categories' => $categories, 'problems' => $problems, ]); } problems/index.blade.php // テンプレート作成 $ mkdir resources/views/problems $ touch resources/views/problems/index.blade.php @extends('layout') @section('content') <div class="container"> <ul class="nav justify-content-center mb-5"> @foreach($categories as $category) <li class="nav-item"> <a class="nav-link" href="#">{{ $category->name }}</a> </li> @endforeach <li class="nav-item"> <a class="nav-link btn btn-success" href="{{ route('categories.create') }}">カテゴリ追加</a> </li> </ul> <div class="row"> <div class="col col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">課題一覧</div> <div class="panel-body"> <a href="#" class="btn btn-default btn-block"> 課題を追加する </a> </div> <table class="table"> <thead> <tr> <th>課題</th> <th></th> <th></th> </tr> </thead> <tbody> @foreach($problems as $problem) <tr class="table-problem"> <td><a href="#">{{ $problem->title }}</a></td> <td><a class='btn btn-primary btn-xs' href="#">編集</a></td> <td> <form action="#" method="POST"> @csrf <input type='submit' value='削除' class='btn btn-danger btn-xs'> </form> </td> </tr> @endforeach </tbody> </table> </nav> </div> </div> </div> @endsection 現在表示されているカテゴリをact状態にする ProblemsController.php return view('problems.index', [ 'categories' => $categories, 'current_category_id' => $category->id, <-これを追加 'problems' => $problems, ]); index.blade.php <li class="nav-item nav-category {{ $current_category_id === $category->id ? 'act' : '' }}"> <a class="nav-link" href="{{ route('problems.index', ['category' => $category->id]) }}">{{ $category->name }}</a> </li> styles.css .nav-category a { color: #333; } .nav-category { border-radius: 4px; } .nav-category:hover, .nav-category.act { background-color: #709e6b; } .nav-category:hover a, .nav-category.act a { color: #fff; } .table-problem:hover, .table-problem.act { background-color: #709e6b; } Problem作成機能 web.php Route::get('/categories/{category}/problems/create', [App\Http\Controllers\ProblemsController::class, 'create'])->name('problems.create'); Route::post('/categories/{category}/problems', [App\Http\Controllers\ProblemsController::class, 'store'])->name('problems.store'); ProblemsController.php /** * 課題の作成ページを表示する */ public function create(Category $category) { return view('problems.create', [ 'category' => $category, ]); } /** * 課題を保存する */ public function store(Category $category, CreateProblem $request) { $problem = new Problem(); $problem->title = $request->title; $category->problems()->save($problem); return redirect()->route('problems.index', [ 'category' => $category, ]); } Requests/CreateProblem.php // Requestsクラスを作成する $ php artisan make:request CreateProblem /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'title' => 'required|max:30' ]; } /** * エラーメッセージを日本語化 * * @return array */ public function attributes() { return [ 'title' => '課題タイトル', ]; } problems/create.blade.php @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">課題を登録する</div> <div class="panel-body"> @if($errors->any()) <div class="alert alert-danger"> <ul> @foreach($errors->all() as $message) <li>{{ $message }}</li> @endforeach </ul> </div> @endif <form action="{{ route('problems.store', ['category' => $category->id]) }}" method="post"> @csrf <div class="form-group"> <label for="title">課題タイトル</label> <input type="text" class="form-control" name="title" id="title" value="{{ old('title') }}" /> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">登録</button> </div> </form> </div> </nav> </div> </div> </div> @endsection 課題作成ページへのリンクを貼る problems/index.blade.php <a href="{{ route('problems.create', ['category' => $category->id]) }}" class="btn btn-default btn-block"> 課題を追加する </a> Problem編集機能 web.php Route::get('/categories/{category}/problems/{problem}/edit', [App\Http\Controllers\ProblemsController::class, 'edit'])->name('problems.edit'); Route::put('/categories/{category}/problems/{problem}/', [App\Http\Controllers\ProblemsController::class, 'update'])->name('problems.update'); ProblemsController.php /** * 課題の編集ページを表示する */ public function edit(Category $category, Problem $problem) { return view('problems.edit', [ 'category' => $category, 'problem' => $problem, ]); } /** * 課題を更新する */ public function update(Category $category, Problem $problem, EditProblem $request) { $categories = Auth::user()->categories()->get(); $problems = $category->problems()->get(); $problem->title = $request->title; $problem->save(); return redirect()->route('problems.index', [ 'categories' => $categories, 'category' => $category, 'current_category_id' => $category->id, 'problems' => $problems, 'problem' => $problem, ]); } problems/edit.blade.php @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">課題を登録する</div> <div class="panel-body"> @if($errors->any()) <div class="alert alert-danger"> <ul> @foreach($errors->all() as $message) <li>{{ $message }}</li> @endforeach </ul> </div> @endif <form action="{{ route('problems.update', ['category' => $category->id, 'problem' => $problem->id]) }}" method="post"> @csrf @method('PUT') <div class="form-group"> <label for="title">課題タイトル</label> <input type="text" class="form-control" name="title" id="title" value="{{ old('title') ?? $problem->title }}" /> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">登録</button> </div> </form> </div> </nav> </div> </div> </div> @endsection Requests/EditProblem.php class EditProblem extends CreateProblem { /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { $rule = parent::rules(); return $rule; } public function attributes() { $attributes = parent::attributes(); return $attributes; } } 課題編集ページへのリンクを貼る problems/index.blade.php <td><a class='btn btn-primary btn-xs' href="{{ route('problems.edit', ['category' => $category->id, 'problem' => $problem->id]) }}">編集</a></td> Problem削除機能 web.php Route::delete('/categories/{category}/problems/{problem}', [App\Http\Controllers\ProblemsController::class, 'destroy'])->name('problems.destroy'); ProblemsController.php /** * 課題を削除する */ public function destroy(Category $category, Problem $problem) { $problem->delete(); return redirect()->route('problems.index', [ 'category' => $category, 'current_category_id' => $category->id, 'problem' => $problem, ]); } problems/index.blade.php <form action="{{ route('problems.destroy', ['category' => $current_category_id, 'problem' => $problem->id]) }}" method="POST"> @csrf @method('DELETE') <input type='submit' value='削除' class='btn btn-danger btn-xs'> </form> Step一覧機能 web.php Route::get('/categories/{category}/problems/{problem}/steps', [App\Http\Controllers\StepsController::class, 'index'])->name('steps.index'); Models/StepsController.php $ php artisan make:model Step Models/Problem.php /** * 課題に対する対策を取得 */ public function step() { return $this->hasOne(Step::class); } datebase/seeds/StepsTableSeeder.php // シーダー作成 $ php artisan make:seeder StepsTableSeeder public function run() { $texts = ['対策1です', '対策2です', '対策3です']; for($i=0; $i<3; $i++) { DB::table('steps')->insert([ 'text' => $texts[$i], 'problem_id' => $i+1, 'created_at' =>Carbon::now(), 'updated_at' =>Carbon::now(), ]); } } // シード実装 $ php artisan db:seed --class=StepsTableSeeder StepsController.php // コントローラー作成 $ php artisan make:controller StepsController use App\Models\Category; use App\Models\Problem; /** * カテゴリに対する対策一覧ページを表示する */ public function index(Category $category, Problem $problem) { $categories = Auth::user()->categories()->get(); $problems = $category->problems()->get(); $step = $problem->step; return view('steps.index', [ 'categories' => $categories, 'current_category_id' => $category->id, 'problems' => $problems, 'step' => $step, ]); } steps/index.blade.php // テンプレート作成 $ mkdir resources/views/steps $ touch resources/views/steps/index.blade.php @extends('layout') @section('content') <div class="container"> <ul class="nav justify-content-center mb-5"> @foreach($categories as $category) <li class="nav-item nav-category {{ $current_category_id === $category->id ? 'act' : '' }}"> <a class="nav-link" href="{{ route('problems.index', ['category' => $category->id]) }}">{{ $category->name }}</a> </li> @endforeach <li class="nav-item"> <a class="nav-link btn btn-success" href="{{ route('categories.create') }}">カテゴリ追加</a> </li> </ul> <div class="row"> <div class="col col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">課題一覧</div> <div class="panel-body"> <a href="{{ route('problems.create', ['category' => $current_category_id]) }}" class="btn btn-default btn-block"> 課題を追加する </a> </div> <table class="table"> <thead> <tr> <th>課題</th> <th></th> <th></th> </tr> </thead> <tbody> @foreach($problems as $problem) <tr class="table-problem"> <td><a href="{{ route('steps.index', ['category' => $current_category_id, 'problem' => $problem->id]) }}">{{ $problem->title }}</a></td> <td><a class='btn btn-primary btn-xs' href="{{ route('problems.edit', ['category' => $current_category_id, 'problem' => $problem->id]) }}">編集</a></td> <td> <form action="{{ route('problems.destroy', ['category' => $current_category_id, 'problem' => $problem->id]) }}" method="POST"> @csrf @method('DELETE') <input type='submit' value='削除' class='btn btn-danger btn-xs'> </form> </td> </tr> @endforeach </tbody> </table> </nav> </div> <div class="col col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">対策</div> <div class="panel-body"> @if(empty($step->id)) <a href="#" class="btn btn-default btn-block"> 対策を追加する </a> @else <div class="row"> <div class="col offset-10"> <a href="#" class="btn btn-primary btn-xs"> 編集 </a> <form action="#" method="POST"> @csrf @method('DELETE') <input type='submit' value='削除' class='btn btn-danger btn-xs'> </form> </div> </div> <div class="card mt-4"> <div class="card-body"> {{$step->text}} </div> </div> @endif </div> </nav> </div> </div> </div> @endsection Step作成機能 web.php Route::get('/categories/{category}/problems/{problem}/steps/create', [App\Http\Controllers\StepsController::class, 'create'])->name('steps.create'); Route::post('/categories/{category}/problems/{problem}/steps', [App\Http\Controllers\StepsController::class, 'store'])->name('steps.store'); StepsController.php /** * 対策の作成ページを表示する */ public function create(Category $category, Problem $problem) { return view('steps.create', [ 'category' => $category, 'current_category_id' => $category->id, 'problem' => $problem, ]); } /** * 対策を保存する */ public function store(Category $category, Problem $problem, CreateStep $request) { $step = new Step(); $step->text = $request->text; $problem->step()->save($step); return redirect()->route('steps.index', [ 'category' => $category, 'problem' => $problem, ]); } CreateStep.php /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'text' => 'required|max:400', ]; } /** * エラーメッセージを日本語化 * * @return array */ public function attributes() { return [ 'text' => '対策テキスト', ]; } steps/create.blade.php @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">対策を登録する</div> <div class="panel-body"> @if($errors->any()) <div class="alert alert-danger"> <ul> @foreach($errors->all() as $message) <li>{{ $message }}</li> @endforeach </ul> </div> @endif <label>課題</label> <div class="card mb-4"> <div class="card-body"> {{$problem->title}} </div> </div> <form action="{{ route('steps.store', ['category' => $category->id, 'problem' => $problem->id]) }}" method="post"> @csrf <div class="form-group"> <label for="text">対策</label> <textarea class="form-control" name="text" id="text">{{ old('text') }}</textarea> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">登録</button> </div> </form> </div> </nav> </div> </div> </div> @endsection Step編集機能 web.php Route::get('/categories/{category}/problems/{problem}/steps/{step}/edit', [App\Http\Controllers\StepsController::class, 'edit'])->name('steps.edit'); Route::put('/categories/{category}/problems/{problem}/steps/{step}', [App\Http\Controllers\StepsController::class, 'update'])->name('steps.update'); StepsController.php /** * 対策の編集ページを表示する */ public function edit(Category $category, Problem $problem, Step $step) { return view('steps.edit', [ 'category' => $category, 'problem' => $problem, 'step' => $step, ]); } /** * 対策を更新する */ public function update(Category $category, Problem $problem, Step $step, EditStep $request) { $step->text = $request->text; $step->save(); return redirect()->route('steps.index', [ 'category' => $category, 'current_category_id' => $category->id, 'problem' => $problem, 'step' => $step, ]); } steps/edit.blade.php @extends('layout') @section('content') <div class="container"> <div class="row"> <div class="col col-md-offset-3 col-md-6"> <nav class="panel panel-success"> <div class="panel-heading">対策を編集する</div> <div class="panel-body"> @if($errors->any()) <div class="alert alert-danger"> <ul> @foreach($errors->all() as $message) <li>{{ $message }}</li> @endforeach </ul> </div> @endif <label>課題</label> <div class="card mb-4"> <div class="card-body"> {{$problem->title}} </div> </div> <form action="{{ route('steps.update', ['category' => $category->id, 'problem' => $problem->id, 'step' => $step->id]) }}" method="post"> @csrf @method('PUT') <div class="form-group"> <label for="text">対策テキスト</label> <textarea class="form-control" name="text" id="text">{{ old('text') ?? $step->text }}</textarea> </div> <div class="text-right"> <button type="submit" class="btn btn-primary">更新</button> </div> </form> </div> </nav> </div> </div> </div> @endsection Requests/EditStep.php class EditStep extends CreateStep { /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { $rule = parent::rules(); return $rule; } public function attributes() { $attributes = parent::attributes(); return $attributes; } 対策削除機能 web.php Route::delete('/categories/{category}/problems/{problem}/steps/{step}', [App\Http\Controllers\StepsController::class, 'destroy'])->name('steps.destroy'); StepsController.php /** * 対策を削除する */ public function destroy(Category $category, Problem $problem, Step $step) { $step->delete(); return redirect()->route('steps.index', [ 'category' => $category, 'current_category_id' => $category->id, 'problem' => $problem, 'step' => $step, ]); } EditStep.php class EditStep extends CreateStep { /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { $rule = parent::rules(); return $rule; } public function attributes() { $attributes = parent::attributes(); return $attributes; } } steps/index.blade.php <form action="{{ route('steps.destroy', ['category' => $current_category_id, 'problem' => $problem->id, 'step' => $step->id]) }}" method="POST"> @csrf @method('DELETE') <input type='submit' value='削除' class='btn btn-danger btn-xs'> </form> 一旦触ってみる カテゴリ削除機能 web.php Route::delete('/categoris/{category}', [App\Http\Controllers\CategoriesController::class, 'destroy'])->name('categories.destroy'); CategoriesController.php /** * カテゴリを削除する */ public function destroy(Category $category) { $category->delete(); return redirect()->route('categories.index'); } categories/index.blade.php <li class="nav-item d-flex"> <a class="nav-link" href="{{ route('problems.index', ['category' => $category->id]) }}"> {{ $category->name }} <form class="d-inline-block" action="{{ route('categories.destroy', ['category' => $category->id]) }}" method="POST"> @csrf @method('DELETE') <input type='submit' value='×' class='btn btn-danger btn-xs'> </form> </a> </li> problems/index.blade.php 上記と同様 steps/index.blade.php 上記と同様 Herokuでデプロイ この記事を参考に 今回は $ git push heroku main さいごに 次はLaravelのマニュアルを読んでいこうと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む