20190829のlaravelに関する記事は7件です。

さくらネットのレンタルサーバーにLaravelを導入してみた

サーバーと契約

さくらネットのHPから簡単に契約できました。
契約したら1、2分でIDとかがメールで届きました。
仮登録という件名のメールにサーバーのパスワードとか入ってました。
これを大事にメモしておく。

自分のアドレスのパス

さくらネットでは(というか他もそうかもしれないが)
/home/hoge/www/
がホームディレクトリになる。
(hogeは自分のユーザー名)

試しに何か転送してみる

試しに適当なindex.htmlを作成して

scp index.html hoge@hoge.sakura.ne.jp:~/www

か、FTPソフトでwww直下においてみる。
ドメイン名にもユーザー名と同じhogeがつくのでハマりやすいです。ていうか軽くハマりました。
メールちゃんとみたほうが良いです。
それで
http://www.hoge.sakura.ne.jp/index.html
にアクセスして開けたらとりあえず自分のサーバー領域は稼働しています。
apachとか自分で立ち上げなくても初めから常時起動しています。

Laravelアプリを転送

本当はgitをうまく使うと楽に管理できるらしいのですが、そういうのはもっと詳しく書いている人がいるのでそちらをみてください。私もそのうちチャレンジするつもりです。
というわけで、今回はゴリ押しでアプリのフォルダごと一式全部さっきのwwwフォルダ直下にscpで送ります。
これはFTPソフトよりターミナルが楽だと思います。

scp -r helloApp hoge@hoge.sakura.ne.jp:~/www

scp -r でフォルダ丸ごとコピーできます。
これで
http://hoge.sakura.ne.jp/helloApp/public/index.php

がアプリのトップページになります。
間のpublicとかなくすやり方も他のページググったら出てきます。

MySQLにつなぐ

繋ぎ方はローカルサーバーより簡単だったので
やり方は他のページを見てもらうとして、
ハマったことだけ書きます。

.envファイルを編集するのですが、sshでサーバーのシェルに入ってvimを使おうとしたらカーソルキーが使えなくて操作できなかった。筆者の環境がたまたまかもしれない。
ですが、さくらの管理ページから入ると専用のWEBエディタが使えてメモ帳みたいな感じで簡単に編集できました。

パスワードなどが違ってDBに接続できない。
ホスト名とか必要なことが一式管理ページにあるのでそれを使えば動きました。

パスワードとかがきちんと合えば、sshでアプリのフォルダにcdで入って
php artisan migration
php artisan db:seed
でローカルのDBがサーバーに再現できちゃいます。すごい。

テーブル名が大文字・小文字が違って繋がらない。
マイグレーションまでできたは良いが、あるはずのテーブルがselectできないと言われた。
まさかと思いつつエラーメッセージに合わせたら動いた。
ローカルでは動いていたんだけど。
どうもMySQLはバージョンによって大文字小文字を同一視したり分けたりするらしいです。
対応は他の方が書いてくれています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel公式で紹介されているNginxの設定の理屈が分からない人向け

概要

Laravelの↓で紹介されているNginxの設定でなぜ動くのかの解説
https://readouble.com/laravel/5.8/ja/deployment.html

解説

location / 部分の設定

↓の部分の try_files の役割は下記の通りになっている。

  • $url にファイルがあるか
  • $url/(/で終わるファイルパスなので、要はディレクトリ)にディレクトリがあるか
  • ↑がなければ、/index.php$query_string へ内部リダイレクトする
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ 部分の設定

基本的に location / の結果としてindex.phpになって内部リダイレクトされている前提になる。
index.phpで内部リダイレクトされるので、location ~ \.php$ にマッチする。

あとは、location ~ \.php$の設定に従い、php-fpmを経由してLaravelの開始スクリプトのindex.phpが実行されるという流れ。

ちなみに、↓部分は、Laravelがいるサーバ(=php-fpmが起動しているサーバ)のLaravelのindex.phpのパスを指定されていれば良いので、

fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;

Laravelのindex.php/laravel/public/index.php にいる場合、↓のようにベタ書きしても動く。

fastcgi_param SCRIPT_FILENAME /laravel/public/index.php;

余談1

ベタ書きした場合でもSCRIPT_FILENAMEの末尾には$query_stringは不要
※Laravel側でちゃんとパラメータは取れる

location /
try_files $uri $uri/ /index.php?$query_string;

try_files $uri $uri/ /index.php;
にするとLaravelにパラメータが来なくなる。

余談2

下記の状態の場合、

リクエスト:http://localhost/aa?aaaa=123
root:/usr/share/nginx/html/

location ~ \.php$に来た時、↓になる。

$realpath_root:/usr/share/nginx/html
$fastcgi_script_name:index.php
$query_string:aaaa=123

$query_stringはphp-fpmに渡す必要ないけど

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelメール送信機能の実装でmailtrapやGmailのSMTPサーバーを使ってみる

内容

Webアプリケーションを制作するに当たり、メール送信機能が必要であることが多々あるかと思います。
今回はLaravel5.8の環境下で、mailtrapを使用と、GmailのSMTPを使用したメール送信の2つのパターンで機能実装をしてみたので、その実装過程を纏めて投稿します。

環境

macOS Mojave 10.14.6
Laravel Framework 5.8.33

1. SMTPサーバー

  • 仮想のSMTPテストサーバーmailtrapを使って簡易的に実装
    • 実際のメールアドレスを使用せず、mailtrapサイト上で内容等を確認できるため、送信機能のテストが簡易的に行える
    • 開発段階で適当に入力したメールアドレスが実際に存在しても送信されることはない
  • GmailのSMTPサーバーを使用して実装
    • 実際にメールが送信される

2. mailtrapを使用する場合の設定

2.1 mailtrapのアカウント作成

メールアドレスで新規登録もしくは、既存のGmailやgithubアカウントも使用できる。
https://mailtrap.io/register/signup?ref=header
スクリーンショット 2019-08-29 16.56.40.png

2.2 SMTPの情報をLaravelの設定に反映させる

2.2.1 設定値の確認

sign in したらdemo inboxを開く
スクリーンショット 2019-08-29 17.02.52.png

IntegrationよりLaravelを選択
スクリーンショット 2019-08-29 17.05.47.png

SMTP settingsの情報をenvもしくはconfig/mail.phpのどちらかに設定(念のため両方)
スクリーンショット 2019-08-29 17.06.59.png

2.2.2 実際に設定する

上記で確認したenvもしくはconfig/mail.phpの値をそれぞれのファイルの該当部にコピペする

.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=4b5fb1796bf652  // コピペの内容のままで良い
MAIL_PASSWORD=22c902aa6ac123  // コピペの内容のままで良い
MAIL_FROM_ADDRESS=hoge@gmail.com  // どのアドレスから送信するかを記載
MAIL_FROM_NAME=name  // 名前を適当に設定

上記内容をconfing/mail.phpでも同様に設定する

設定完了後は各種キャッシュクリア

$ php artisan cache:clear
$ php artisan config:cache

3. GmailのSMTPを使う場合の設定

GmailのSMTPを使用する場合はセキュリティの都合上、Gmailアカウントの設定変更が必要となる。

  • 安全性の低いアプリ許可をオンにする方法
  • 二段階認証を有効にし、アプリパスワードを発行する方法

3.1 安全性の低いアプリ許可をオンにする方法

  • 安全性の低いアプリの許可をオンにする
    • https://myaccount.google.com/lesssecureapps
    • こちらは、二段階認証を有効にしている場合はオンにできない仕様である。すでに2段階認証が有効にされている場合は設定を解除しても良いが、下記、二段階認証有効下でアプリパスワードを発行する方法をオススメする
  • .envファイルを下記の通り設定する
.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=hoge@example.com  // メールアドレスを記載(下のFROMと同じで良い)
MAIL_PASSWORD=hogehogehoge  // Gmailアカウントの生のパスワード
MAIL_FROM_ADDRESS=hoge@example.com  // どのアドレスから送信するかを記載
MAIL_FROM_NAME=name  // 名前を適当に設定

上記内容をconfing/mail.phpでも同様に設定する

設定完了後は各種キャッシュクリア

$ php artisan cache:clear
$ php artisan config:cache

3.2 二段階認証を有効にし、アプリパスワードを発行する方法

  • 二段階認証の有効化
  • アプリパスワードの発行
    • 簡単に言うとenvファイルで設定するMAIL_PASSWORDに記載するパスワードを発行すること
    • ログインしたアカウントのGoogleアカウントページのセキュリティよりアプリパスワードを設定する。
      • アプリを選択では「メール」を選択する
      • デバイスを選択では使用しているデバイスを選択する
    • 設定が終わると16桁のアプリパスワードが発行されるため、それをenvファイルのMAIL_PASSWORDに記載
    • 注)デプロイするアプリケーションごとに発行する必要があり、使い回しだと認証が通らないので注意。(localで使用したものをデプロイ先で使えない)

スクリーンショット 2019-08-29 18.38.27.png

envの設定値は、「安全性の低いアプリ許可をオンにする方法」の場合と比較し、MAIL_PASSWORDの内容が異なる

.env
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587   // 587にする
MAIL_USERNAME=hoge@example.com  // メールアドレスを記載(下のFROMと同じで良い)
MAIL_PASSWORD=hogehogehoge  // 発行したアプリパスワードの設定
MAIL_FROM_ADDRESS=hoge@example.com  // どのアドレスから送信するかを記載
MAIL_FROM_NAME=name  // 名前を適当に設定

上記内容をconfing/mail.phpでも同様に設定する

設定完了後は各種キャッシュクリア

$ php artisan cache:clear
$ php artisan config:cache

4. Mailableクラス

設定値の入力が完了すれば、次は機能面の実装
Mailableクラスでは送信するメールの情報やその内容を設定できる

4.1 Mailableクラスの作成

次のコマンドを実行すると、app/Mail/SamleMail.phpを生成される
今回はクラス名をSampleMailとする

$ php artisan make:mail {クラス名}
# 今回、作成するクラス名
$ php artisan make:mail SampleMail
  • 生成されたapp/Mail/SampleMailbuild()メソッドに送信するメールの送信元情報や、メールの内容を追記する
  • メールの送信元や、メールの内容で状況に応じて変数を使用したい場合があるが、変数を使用する場合としない場合と2通り説明する

4.2 変数を使用せず、決まった送信元から決まった内容を送信する場合

app/Mail/SamleMail.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class SampleMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
      return $this
          ->from('hoge@sample.com') // 送信元
          ->subject('テスト送信') // メールタイトル
          ->view('mail.send'); // メール本文のテンプレートとなるviewを設定
    }
}

4.3 変数を受け取る場合

今回、下記の例では次の変数$contentをControllerから受け取ることとする
$content = ['name' => 'fuga', 'mail' => 'fuga@example.com'];
※Controller側の設定は次項で説明

app/Mail/SamleMail.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class SampleMail extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */

    // 引数で受け取る変数
    protected $content;
    // コンストラクタ設定
    public function __construct($content)
    {
        // 引数で受け取ったデータを変数にセット
        $this->content = $content;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
      return $this
          ->from('hoge@exapmle.com') // 送信元
          ->subject('テスト送信') // メールタイトル
          ->view('mail.send') // メール本文のテンプレート
          ->with(['content' => $this->content]);  // withでセットしたデータをviewへ渡す
    }
}

5. Controllerの設定

Controller側では送信先とMailableクラスの振り分けを行う

Controller
use App\Mail\OrderMail;
use Illuminate\Support\Facades\Mail;

public function store(Request $request){
  // フォームからのリクエストデータ全てを$contentに代入
  $content = $request->all();

// 特に変数を渡さない場合
Mail::to($content->email)->send(new SapmleMail);
// データの入った変数を渡す場合
Mail::to($content->email)->send(new SampleMail($content));

6. メール本文のテンプレート

Mailableクラスで設定したviewのメール本文のテンプレートの作成

views/mail/send.blade.php
// withで変数を受け取った場合は変数を使用できる
{{ $contact->name }} 
メール送信完了

7. メールの送信

以上で、メール送信機能が完成。
mailtrapではこのような感じでで表示されるようになる。

スクリーンショット 2019-08-29 17.09.39.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでリレーションされているデータをpaginateする

色々躓いたのでまとめておきます。

前提

PHP 7.0
Laravel 5.5

データ構造

Work

id category_id title
1 1 なんかのしごと

WorkCategory

id name
1 未分類

やりたいこと

上記データ構造のデータを下記のような形で返すAPIを作りたい

{
  "id": "1",
  "category_name": "未分類",
  "title": "なんかのしごと" 
}

かつ、Laravelさんのページネーション情報つきで!

1対1リレーションするようにモデルを変更する

Eloquent:リレーション 5.5 Laravel

Work.php
class Work extends Model {
    public function workCategory() {
        return $this->hasOne('App\models\WorkCategory', 'id', 'category_id');
    }
}

躓いたこと

workCategory ではなく categoryName にして名前だけ直接取ろうとして、なんか色々だめでした。
素直に関連するモデル名にしたらすんなり動きました。

下記だめだったコード

だめだったコード
class Work extends Model {
    public function categoryName() {
        return $this->hasOne('App\models\WorkCategory', 'id', 'category_id')->name;
    }
}

主に name が存在しないという感じで怒られていました。
また、名前だけを取る方法をやめ WorkCategory 自体を持つように変えています。

EagerLoad を使う

Work::paginate(9); ではなく Work::with('workCategory')->paginate(9); を使う。

WorkRepository.php
class WorkRepository {

    public function getPaginateWorks() {
        return Work::with('workCategory')->paginate(9);
    }
}

Resources を用意してJSONに変換する

Laravel 5.5 Eloquent: APIリソース のようにモデルをJSONに変換する層が用意されているみたいです。

$ php artisan make:resource PaginatedWorks --collection

artisan にリソースを作ってもらって、先程の変換ロジックを入れます。

PaginatedWorks.php
class PaginatedWorks extends ResourceCollection {
    public function toArray($request) {
        return ['data' => $this->collection->transform([$this, 'map'])];
    }

    public function map($work) {
        return [
            'id' => $work->id,
            'category_name' => $work->workCategory->name,
            'title' => $work->title
        ];
    }
}

paginate 内のデータ変換には transform メソッドを使うと良いみたいです。

callable は配列で渡してもOK

Resouces を知る前に書いていたので Repository になっています

WorkRepository.php
class WorkRepository {

    public function getPaginateWorks() {
        $works = Work::with('workCategory')->paginate(9);
        $works->getCollection()->transform([$this, 'map']);
        return $works;
    }

    public function map(Work $work) {
        return [
            'id' => $work->id,
            'category_name' => $work->workCategory->name,
            'title' => $work->title
        ];
    }
}

はじめのうち transform$this->map を渡していて
Undefined property: App\\Repositories\\WorkRepository::$map と怒られていました。
調べたところ [$this, 'map'] という風に配列で渡してやれば実行してくれるとのこと。
渡す配列は1つ目にインスタンス、2つ目に実行するメソッド名の文字列。

下記だめだったコード

だめだったコード
class WorkRepository {
    public function getPaginateWorks() {
        $works = Work::with('workCategory')->paginate(9);
        $works->getCollection()->transform($this->map);
        return $works;
    }

    private function map(Work $work) {
        return [
            'id' => $work->id,
            'category_name' => $work->workCategory->name,
            'title' => $work->title
        ];
    }
}

渡したいメソッドを private で定義していたところも躓いていました。
なお PHP7.1 以上であれば private で渡せる方法がある模様です。

結果

WorkController.php
class WorksController extends Controller {
    public function __construct() {
    }

    public function index(Request $request) {
        $paginatedWorks = (new WorkRepository())->getPaginatedWorks();
        return new PaginatedWorks($paginatedWorks);
    }
}
Work.php
class Work extends Model {
    public function workCategory() {
        return $this->hasOne('App\models\WorkCategory', 'id', 'category_id');
    }
}
WorkRepository.php
class WorkRepository {
    public function getPaginateWorks() {
        return Work::with('workCategory')->paginate(9);
    }
}
PaginatedWorks.php
class PaginatedWorks extends ResourceCollection {
    public function toArray($request) {
        return ['data' => $this->collection->transform([$this, 'map'])];
    }

    public function map($work) {
        return [
            'id' => $work->id,
            'category_name' => $work->workCategory->name,
            'title' => $work->title
        ];
    }
}
Response
{
  "data": [
    {
      "id": 1,
      "category_name": "\u672a\u5206\u985e",
      "title": "\u30af\u30ec\u30b9\u30c8\u30db\u30fc\u30eb\u30c7\u30a3\u30f3\u30b0\u30b9 \u30b3\u30fc\u30dd\u30ec\u30fc\u30c8\u30b5\u30a4\u30c8\u5236\u4f5c"
    }
  ],
  "links": {
    "first": "\/api\/works?page=1",
    "last": "\/api\/works?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 1,
    "path": "\/backoffice\/api\/works",
    "per_page": 9,
    "to": 1,
    "total": 1
  }
}

Responsepath は少し変えてます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CodenvyでLaravelデビューする

何するの

CodenvyでLaravelの実行環境を作るよ。
個人用メモ
## なんか画像が入らないので後で差し込む

事前準備

Codenvyのアカウント登録しておく

ワークスペースを作る

Create WorkSpaceからワークスペースを作成する。
NAMEは任意のワークスペース名を指定。
TEAMは個人ならpersonalで。
SELECT STACKはPHPを選択。
あとは基本的にいじらなくてよし。

Laravelプロジェクトを作る

Create Project...からプロジェクトを作成する。
PHPのComposerを指定。
Nameは任意のプロジェクト名を指定。
Descriptionも任意で記入。
Nextで次に進む。
Package Namelaravel/laravelを指定。
Create

Laravelプロジェクトを実行するための準備

ファイル名を直す

.env.sampleファイルを.envに修正する。

cd [各プロジェクト名]
cp -p .env.example .env
php artisan key:generate

実行用のコマンドを作る

Create new commandからコマンド作成ダイアログを表示する。
Nameは任意のコマンド名を指定。
Command lineには以下を指定。

cd ${current.project.path} && php artisan serve --host=0.0.0.0 --port=3306

Apply toは当プロジェクトのApplicableYesに設定する。
Preview URLは以下を指定。

http://${server.port.3306}

Save

実行してみよう

上で登録した実行用のコマンドを実行してみる。
実行はCreate new commandしたところから。

OK!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel 5.7でControllerのファイル名を少し変更(大文字)しただけなのに、Controllerファイルが見つからないエラーが出るようになった

問題

すでに作ったControllerファイル名を変更(大文字・小文字)したら、ファイルが見つからないエラーが出てサイトが動かなくなった。表示されたエラーは以下の通り:

ErrorException (E_WARNING)
include(/hogehoge/backend/vendor/composer/../../app/Http/Controllers/NameOfController.php): 
failed to open stream: No such file or directory

環境と経緯

  • Laravel 5.7使用。
  • "php artisan make:controller nameOfController"でコントローラを追加。
  • 自動生成されたファイルの名前(nameOfController.php)を、のちに"NameOfController.php"へ変更。
  • ファイル名を変更した後で、routes/web.phpには、"Route::get('/entrance', 'NameOfController@hoge')->name('hoge');"を追加。
  • 前述の問題が発生。ErrorException・No such file or directoryエラーが発生し、サイトが動かなくなった。

解決策

ターミナルで、"composer dump-autoload"をlaravelプロジェクトのルートディレクトリで実行する。こちらのブログが参考になりました。

背景

コントローラを作っていくうちに、コントローラファイル名のケーススタイルがバラバラになってきた(camelCase名で作ったコントローラよりPascalCaseの方が多くなってきた)ため、手に負えなくなる前に統一しておこうと思った途端に起きた問題でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Homeateadで立ち上げたLaravel環境にsequel ProでDB接続

なんだかんだ毎月記事を投稿していて8月は何もアウトプット出来ていなかったので急ぎ足で記事を書く。。。
最近Laravelを使った開発をしていて自宅のMacにもLaravel環境を構築してDB接続にsequel proを使ったので記事に残します。

環境構築を終えホスト設定を済ませブラウザからLaravelのトップページが表示が出来ているという前提です。

データベースに接続するためにSequel proを使用します。

作成したプロジェクトディレクトリ内にある.envファイルを開くとDBの情報が記載されています。
Image from Gyazo
Image from Gyazo

記載されいる情報を確認しながらsequel proに必要な情報を入力すれば立ち上げている仮想環境内のDBに接続できます。

Image from Gyazo

  • 名前
    • localhostやtest-laravelなど、任意に指定できます。
  • ホスト
    • これはhomestead.ymlに記述してあるIPを参照すればOKです。
homestead.yml
ip: "192.168.xxx.xxx"
  • ユーザ名/パスワード/ポート
    • 自身の.envファイルを参照すればOKです。
DB_USERNAME=homestead
DB_PASSWORD=xxxxxx
DB_PORT=3306

これだけでDBへ接続できると思います。
コマンドラインからもDB情報は見れますがクライアントツールを上手く使えば見やすくなります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む