タグ: PHP-Laravel
[PHP-Laravel]本番サーバー構築手順(GitHub->Heroku編)
Heroku公式
https://devcenter.heroku.com/articles/getting-started-with-laravel
Heroku
Heroku クライアント
https://devcenter.heroku.com/articles/heroku-cli#windows
Git
Heroku/Application 設定
# php artisan key:generate --show の結果 # Laravel直下の.env APP_KEYと一致する必要あり heroku config:set APP_KEY=... # ルートディレクトリの設定 echo "web: vendor/bin/heroku-php-apache2 public/" > Procfile
Heroku/Database設定
config/database.php
'default' => env('DB_CONNECTION', 'pgsql'),
Git設定
git remote add origin https://github.com/(heroku_appname).git
リポジトリ作成・登録
git init git add -A . git commit -m "comment"
デプロイ
git push heroku master
[PHP-Laravel]ローカル開発環境構築手順(Windows10編)
Xampp
https://www.apachefriends.org/jp/index.html
事前準備
sudo apt-get update sudo apt-get upgrade
PHP
sudo apt-get install php7.2 sudo apt-get install php7.2-zip sudo apt-get install php7.2-mbstring sudo apt-get install php7.2-dom
Composer
curl -sS https://getcomposer.org/installer | php
Laravel
composer global require "laravel/installer" export PATH="$PATH":$HOME/.composer/vendor/bin
プロジェクト作成
laravel new sampleapp
起動
cd sampleapp php artisan serve
確認
[PHP-Laravel]ローカル開発環境構築手順(Mac編)
MAMP
Composer
# ダウンロード
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
php composer-setup.php
php -r "unlink('composer-setup.php');"
# パスを設定
mv composer.phar /usr/local/bin/composer
# バージョン確認
composer -V
Laravel
composer global require "laravel/installer" export PATH="$PATH":$HOME/.composer/vendor/bin
プロジェクト作成
laravel new (appname)
起動
php artisan serve
確認
http://localhost:8000
[PHP-Laravel]MVCを理解しよう-掲示板サービス作成手順
プロジェクトの作成
laravel new samplepj
環境設定
DB設定を行う。.envファイルを編集する
データベース テーブルの作成
マイグレーションファイルの生成
php artisan make:migration create_posts_table --create=posts php artisan make:migration create_comments_table --create=comments
database/migrations/yyyy_mm_dd_HHMISS_create_posts_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title', 50);
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
database/migrations/yyyy_mm_dd_HHMISS_create_comments_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCommentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('post_id');
$table->text('body');
$table->timestamps();
$table->foreign('post_id')->references('id')->on('posts');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('comments');
}
}
マイグレーションファイルの実行
php artisan migrate
ルーティングの設定
routes/web.php
Route::get('/', 'PostsController@index')->name('top');
Route::resource('posts', 'PostsController', ['only' => ['create', 'store', 'show', 'edit', 'update', 'destroy']]);
Route::resource('comments', 'CommentsController', ['only' => ['store']]);
コントローラーの作成
コントローラーファイルの生成
php artisan make:controller PostsController php artisan make:controller CommentsController
app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
class PostsController extends Controller
{
public function index()
{
// $posts = Post::orderBy('created_at', 'desc')->get();
// $posts = Post::orderBy('created_at', 'desc')->paginate(10);
$posts = Post::with(['comments'])->orderBy('created_at', 'desc')->paginate(10);
return view('posts.index', ['posts' => $posts]);
}
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
$params = $request->validate([
'title' => 'required|max:50',
'body' => 'required|max:2000',
]);
Post::create($params);
return redirect()->route('top');
}
public function show($post_id)
{
$post = Post::findOrFail($post_id);
return view('posts.show', [
'post' => $post,
]);
}
public function edit($post_id)
{
$post = Post::findOrFail($post_id);
return view('posts.edit', [
'post' => $post,
]);
}
public function update($post_id, Request $request)
{
$params = $request->validate([
'title' => 'required|max:50',
'body' => 'required|max:2000',
]);
$post = Post::findOrFail($post_id);
$post->fill($params)->save();
return redirect()->route('posts.show', ['post' => $post]);
}
public function destroy($post_id)
{
$post = Post::findOrFail($post_id);
\DB::transaction(function () use ($post) {
$post->comments()->delete();
$post->delete();
});
return redirect()->route('top');
}
}
app/Http/Controllers/CommentsController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
class CommentsController extends Controller
{
public function store(Request $request)
{
$params = $request->validate([
'post_id' => 'required|exists:posts,id',
'body' => 'required|max:2000',
]);
$post = Post::findOrFail($params['post_id']);
$post->comments()->create($params);
return redirect()->route('posts.show', ['post' => $post]);
}
}
ビューの作成
resources/views/layout.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Laravel BBS</title>
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous"
>
</head>
<body>
<header class="navbar navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{{ url('') }}">
Laravel BBS
</a>
</div>
</header>
<div>
@yield('content')
</div>
</body>
</html>
resources/views/posts/index.blade.php
@extends('layout')
@section('content')
<div class="mb-4">
<a href="{{ route('posts.create') }}" class="btn btn-primary">
投稿を新規作成する
</a>
</div>
<div class="container mt-4">
@foreach ($posts as $post)
<div class="card mb-4">
<div class="card-header">
{{ $post->title }}
</div>
<div class="card-body">
<p class="card-text">
{!! nl2br(e(str_limit($post->body, 200))) !!}
</p>
</div>
<div class="card-footer">
<span class="mr-2">
投稿日時 {{ $post->created_at->format('Y.m.d') }}
</span>
@if ($post->comments->count())
<span class="badge badge-primary">
コメント {{ $post->comments->count() }}件
</span>
@endif
<form class="mb-4" method="POST" action="{{ route('comments.store') }}">
@csrf
<input
name="post_id"
type="hidden"
value="{{ $post->id }}"
>
<div class="form-group">
<label for="body">
本文
</label>
<textarea
id="body"
name="body"
class="form-control {{ $errors->has('body') ? 'is-invalid' : '' }}"
rows="4"
>{{ old('body') }}</textarea>
@if ($errors->has('body'))
<div class="invalid-feedback">
{{ $errors->first('body') }}
</div>
@endif
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">
コメントする
</button>
</div>
</form>
</div>
</div>
<p class="card-text">
{!! nl2br(e(str_limit($post->body, 200))) !!}
</p>
<a class="card-link" href="{{ route('posts.show', ['post' => $post]) }}">
続きを読む
</a>
@endforeach
<div class="d-flex justify-content-center mb-5">
{{ $posts->links() }}
</div>
</div>
@endsection
resources/views/posts/create.blade.php
@extends('layout')
@section('content')
<div class="container mt-4">
<div class="border p-4">
<h1 class="h5 mb-4">
投稿の新規作成
</h1>
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<fieldset class="mb-4">
<div class="form-group">
<label for="title">
タイトル
</label>
<input
id="title"
name="title"
class="form-control {{ $errors->has('title') ? 'is-invalid' : '' }}"
value="{{ old('title') }}"
type="text"
>
@if ($errors->has('title'))
<div class="invalid-feedback">
{{ $errors->first('title') }}
</div>
@endif
</div>
<div class="form-group">
<label for="body">
本文
</label>
<textarea
id="body"
name="body"
class="form-control {{ $errors->has('body') ? 'is-invalid' : '' }}"
rows="4"
>{{ old('body') }}</textarea>
@if ($errors->has('body'))
<div class="invalid-feedback">
{{ $errors->first('body') }}
</div>
@endif
</div>
<div class="mt-5">
<a class="btn btn-secondary" href="{{ route('top') }}">
キャンセル
</a>
<button type="submit" class="btn btn-primary">
投稿する
</button>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
resources/views/posts/show.blade.php
@extends('layout')
@section('content')
<div class="container mt-4">
<div class="border p-4">
<div class="mb-4 text-right">
<a class="btn btn-primary" href="{{ route('posts.edit', ['post' => $post]) }}">
編集する
</a>
</div>
<form
style="display: inline-block;"
method="POST"
action="{{ route('posts.destroy', ['post' => $post]) }}"
>
@csrf
@method('DELETE')
<button class="btn btn-danger">削除する</button>
</form>
<h1 class="h5 mb-4">
{{ $post->title }}
</h1>
<p class="mb-5">
{!! nl2br(e($post->body)) !!}
</p>
<section>
<h2 class="h5 mb-4">
コメント
</h2>
@forelse($post->comments as $comment)
<div class="border-top p-4">
<time class="text-secondary">
{{ $comment->created_at->format('Y.m.d H:i') }}
</time>
<p class="mt-2">
{!! nl2br(e($comment->body)) !!}
</p>
</div>
@empty
<p>コメントはまだありません。</p>
@endforelse
</section>
</div>
</div>
@endsection
resources/views/posts/edit.blade.php
@extends('layout')
@section('content')
<div class="container mt-4">
<div class="border p-4">
<h1 class="h5 mb-4">
投稿の編集
</h1>
<form method="POST" action="{{ route('posts.update', ['post' => $post]) }}">
@csrf
@method('PUT')
<fieldset class="mb-4">
<div class="form-group">
<label for="title">
タイトル
</label>
<input
id="title"
name="title"
class="form-control {{ $errors->has('title') ? 'is-invalid' : '' }}"
value="{{ old('title') ?: $post->title }}"
type="text"
>
@if ($errors->has('title'))
<div class="invalid-feedback">
{{ $errors->first('title') }}
</div>
@endif
</div>
<div class="form-group">
<label for="body">
本文
</label>
<textarea
id="body"
name="body"
class="form-control {{ $errors->has('body') ? 'is-invalid' : '' }}"
rows="4"
>{{ old('body') ?: $post->body }}</textarea>
@if ($errors->has('body'))
<div class="invalid-feedback">
{{ $errors->first('body') }}
</div>
@endif
</div>
<div class="mt-5">
<a class="btn btn-secondary" href="{{ route('posts.show', ['post' => $post]) }}">
キャンセル
</a>
<button type="submit" class="btn btn-primary">
更新する
</button>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
モデルの作成
モデルファイルの生成
php artisan make:factory PostFactory --model=Post php artisan make:factory CommentFactory --model=Comment
app/Post.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = [
'title',
'body',
];
public function comments()
{
return $this->hasMany('App\Comment');
}
}
app/Comment.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $fillable = [
'body',
];
public function post()
{
return $this->belongsTo('App\Post');
}
}