20200211のlaravelに関する記事は11件です。

Laravel でModelの配列を created_at , updated_at で並べ替えたいとき

TL;DR

usort を使って行います

$posts = $user->posts->toArray();
usort($posts, function ($a, $b) {
    if ($a['updated_at'] != $b['updated_at']) {
        return ($a['updated_at'] < $b['updated_at']) ? +1 : -1;
    }

    if ($a['created_at'] != $b['created_at']) {
        return ($a['created_at'] < $b['created_at']) ? +1 : -1;
    }

    return ($a['id'] < $b['id']) ? +1 : -1;
});

デモンストレーション

Postモデルのデータをupdated_at > created_at > id の評価順で降順に並べ替えます

データの準備

  • php artisan make:seeder でSeederを生成
$ php artisan make:seeder PostsTableSeeder
  • 生成したSeederを編集
<?php

use Faker\Factory as Faker;
use App\Post;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class PostsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        DB::table('posts')->truncate();
        $faker = Faker::create('en_US');

        for ($i = 0; $i < 5; $i++) {
            $created_at = $faker->dateTime;
            $updated_at = $faker->dateTime;
            while ($created_at > $updated_at) {
                // created_at > updated_atのデータは気持ち悪いため
                $updated_at = $faker->dateTime;
            }

            Post::create([
                "title" => $faker->text(20),
                "content" => $faker->text(100),
                "writer_id" => 1,
                "created_at" => $created_at,
                "updated_at" => $updated_at,
            ]);
        }
    }
}

  • php artisan db:seed でデータ登録
$ php artisan db:seed
Seeding: PostsTableSeeder
Seeded:  PostsTableSeeder (0.12 seconds)
Database seeding completed successfully

usort で並べ替え

PHPには、配列を並べ替える関数が多く用意されています
https://www.php.net/manual/ja/array.sorting.php

今回は複雑な並べ替えをしたいため、usortを使用します
usortは第1引数にソートしたい配列を、第2引数にユーザ定義の比較関数を渡して使用します
この比較関数は比較対象の2つの値を引数に持ち、正の数が返されたときに第1引数が大きい、
負の数が返されたとき第1引数が小さいと判定されます

// Post(オブジェクト)の配列を、Post(配列)の配列に変換する
$posts = $user->posts->toArray();
// 第1引数にPostの配列を、第2引数に$a、$b(を
// 引数に持つコールバックを渡す
usort($posts, function ($a, $b) {
    if ($a['updated_at'] != $b['updated_at']) {
        // 両者のupdated_atが異なる、つまり比較が可能
        return ($a['updated_at'] < $b['updated_at']) ? +1 : -1;
    }

    if ($a['created_at'] != $b['created_at']) {
        return ($a['created_at'] < $b['created_at']) ? +1 : -1;
    }

    // 両者のupdated_at、created_atが同じ場合、idで比較
    return ($a['id'] < $b['id']) ? +1 : -1;
});
  • ソート前のデータ
array:5 [
  0 => array:6 [
    "id" => 1
    "title" => "Quo corrupti autem."
    "content" => "Esse rerum facere excepturi. Possimus eum inventore voluptas necessitatibus."
    "writer_id" => 1
    "created_at" => "1977-07-07 11:20:57"
    "updated_at" => "1994-10-21 08:47:34"
  ]
  1 => array:6 [
    "id" => 2
    "title" => "Id similique magni."
    "content" => "Beatae sed in qui tempora iste omnis. Ab sed alias unde dolorum quae. Enim laborum quos ut."
    "writer_id" => 1
    "created_at" => "1993-07-08 01:36:37"
    "updated_at" => "2010-04-29 20:39:01"
  ]
  2 => array:6 [
    "id" => 3
    "title" => "Maxime rem."
    "content" => "Ut alias nisi sit sunt nulla. Sit illo et necessitatibus dolore eaque placeat nesciunt iste."
    "writer_id" => 1
    "created_at" => "2013-06-27 15:33:04"
    "updated_at" => "2018-04-30 20:57:11"
  ]
  3 => array:6 [
    "id" => 4
    "title" => "A neque quo sit."
    "content" => "Unde explicabo iure est dolor maiores sit. Occaecati assumenda atque exercitationem quos nam omnis."
    "writer_id" => 1
    "created_at" => "2006-04-26 06:04:26"
    "updated_at" => "2009-12-17 18:17:15"
  ]
  4 => array:6 [
    "id" => 5
    "title" => "Ullam quia beatae."
    "content" => "Commodi numquam fugiat eveniet quas. Dolore repellat enim veniam libero."
    "writer_id" => 1
    "created_at" => "2015-04-06 09:17:58"
    "updated_at" => "2020-01-16 19:21:05"
  ]
]
  • ソート後のデータ
array:5 [
  0 => array:6 [
    "id" => 5
    "title" => "Ullam quia beatae."
    "content" => "Commodi numquam fugiat eveniet quas. Dolore repellat enim veniam libero."
    "writer_id" => 1
    "created_at" => "2015-04-06 09:17:58"
    "updated_at" => "2020-01-16 19:21:05"
  ]
  1 => array:6 [
    "id" => 3
    "title" => "Maxime rem."
    "content" => "Ut alias nisi sit sunt nulla. Sit illo et necessitatibus dolore eaque placeat nesciunt iste."
    "writer_id" => 1
    "created_at" => "2013-06-27 15:33:04"
    "updated_at" => "2018-04-30 20:57:11"
  ]
  2 => array:6 [
    "id" => 2
    "title" => "Id similique magni."
    "content" => "Beatae sed in qui tempora iste omnis. Ab sed alias unde dolorum quae. Enim laborum quos ut."
    "writer_id" => 1
    "created_at" => "1993-07-08 01:36:37"
    "updated_at" => "2010-04-29 20:39:01"
  ]
  3 => array:6 [
    "id" => 4
    "title" => "A neque quo sit."
    "content" => "Unde explicabo iure est dolor maiores sit. Occaecati assumenda atque exercitationem quos nam omnis."
    "writer_id" => 1
    "created_at" => "2006-04-26 06:04:26"
    "updated_at" => "2009-12-17 18:17:15"
  ]
  4 => array:6 [
    "id" => 1
    "title" => "Quo corrupti autem."
    "content" => "Esse rerum facere excepturi. Possimus eum inventore voluptas necessitatibus."
    "writer_id" => 1
    "created_at" => "1977-07-07 11:20:57"
    "updated_at" => "1994-10-21 08:47:34"
  ]
]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

twitterの情報発信を助けるWebサービス「EMOEMO」公開延期します。

EMOEO延期の理由はこちらから

!

はじめに

初めまして!てらって呼んでください:relaxed:
簡単に自己紹介をするとごみくずプログラミング初学者です。(3ヶ月目)
現在個人開発中のWEBサービス(EMOEMO)を紹介してみようと思い記事を書いています。

EMOEMOはどんなサービス?

メモアプリからそのままツイート出来ます!
EMOEMOの提供するサービスの基本はこの1点です。
メモを管理できたりする機能も随時実装予定ですが、これはおまけみたいなもんです。

EMOEMOは何を解決するの?

プログラミング勉強をしていてわからない単語を調べる機会はあるかとおもいます。
私の場合はかなり多く単語をgooglekeepにメモっておいて、後からまとめて調べてそれをコピペしアウトプットとしてtwitterに呟いていました。
ある時、このコピペがだる過ぎてこれを解決したくてEMOEMOを製作し始めました。

使ってみて欲しい人は?

  • 情報発信を始めた人
  • まさに1ヶ月前の自分とこれからの自分です。
  • twitterjのタイムラインを見過ぎてしまって、時間を無駄にしてしまっているなと感じている人

今、進捗は感じなの?

LP部
スクリーンショット 2020-02-11 17.37.25.png
スクリーンショット 2020-02-11 17.37.29.png

CRUD機能部(作って読めて編集できて削除出来るアプリケーションの基本機能の事です)
ここでメモを追加したり編集できたりできます。

スクリーンショット 2020-02-11 17.16.36.png
メモをTwitterに送信できます。
スクリーンショット 2020-02-11 17.55.22.png

ここまで作ってみての感想など。

やはり実現したい事は高度な技術を使っている場合が多く大変です。時間の制約がある以上そぎ落とすべき肉は必ずあるし、やりたい実装の取捨選択が大変でした。これこんな難しいの!?みたいな事はザラだし、逆にめっちゃむずいと思っていたけど簡単やんこれみたいな感じな事もよくあります。

最低限必要な機能を実装し、使ってもらう事が一番だと思っているので必要な機能のみを実装しとりあえず、使ってみてもらう事を1番の目標設定にしています。

2月の14日にデプロイします!

スケジュールはこんな感じにしています。

スクリーンショット 2020-02-11 20.55.22.png

最後に!!!!!!

もし最後まで読んでくださっていたら方がいたらいいねをお願いします!

またね!

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

twitterの情報発信を助けるWebサービス「EMOEMO」を2月の14日に公開します!

はじめに

初めまして!てらって呼んでください:relaxed:
簡単に自己紹介をするとごみくずプログラミング初学者です。(3ヶ月目)
現在個人開発中のWEBサービス(EMOEMO)を紹介してみようと思い記事を書いています。

EMOEMOはどんなサービス?

メモアプリからそのままツイート出来ます!
EMOEMOの提供するサービスの基本はこの1点です。
メモを管理できたりする機能も随時実装予定ですが、これはおまけみたいなもんです。

EMOEMOは何を解決するの?

プログラミング勉強をしていてわからない単語を調べる機会はあるかとおもいます。
私の場合はかなり多く単語をgooglekeepにメモっておいて、後からまとめて調べてそれをコピペしアウトプットとしてtwitterに呟いていました。
ある時、このコピペがだる過ぎてこれを解決したくてEMOEMOを製作し始めました。

使ってみて欲しい人は?

  • 情報発信を始めた人
  • まさに1ヶ月前の自分とこれからの自分です。
  • twitterjのタイムラインを見過ぎてしまって、時間を無駄にしてしまっているなと感じている人

今、進捗は感じなの?

LP部
スクリーンショット 2020-02-11 17.37.25.png
スクリーンショット 2020-02-11 17.37.29.png

CRUD機能部(作って読めて編集できて削除出来るアプリケーションの基本機能の事です)
ここでメモを追加したり編集できたりできます。

スクリーンショット 2020-02-11 17.16.36.png
メモをTwitterに送信できます。
スクリーンショット 2020-02-11 17.55.22.png

ここまで作ってみての感想など。

やはり実現したい事は高度な技術を使っている場合が多く大変です。時間の制約がある以上そぎ落とすべき肉は必ずあるし、やりたい実装の取捨選択が大変でした。これこんな難しいの!?みたいな事はザラだし、逆にめっちゃむずいと思っていたけど簡単やんこれみたいな感じな事もよくあります。

最低限必要な機能を実装し、使ってもらう事が一番だと思っているので必要な機能のみを実装しとりあえず、使ってみてもらう事を1番の目標設定にしています。

2月の14日にデプロイします!

スケジュールはこんな感じにしています。

スクリーンショット 2020-02-11 20.55.22.png

最後に!!!!!!

もし最後まで読んでくださっていたら方がいたらいいねをお願いします!

またね!

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

星5段階評価プルダウンメニューの作成手順

星5段階評価プルダウンメニューを導入したのでその手順をメモします

configディレクトリ下にデータをつくる

score.php
<?php
  return array(
    '1' => '☆',
    '2' => '☆☆',
    '3' => '☆☆☆',
    '4' => '☆☆☆☆',
    '5' => '☆☆☆☆☆',
  );
?>

ビューでプルダウンを表示する

create.blade.php
<select type="text" name="review">
    @foreach(config('score') as $key => $score)
        <option value="{{ $key }}">{{ $score }}</option>
    @endforeach
</select>

プルダウンで選択して送信したデータを取得する

viewの記述(if文を使用する場合)

detail.blade.php
    @if (取得したいデータ == 1)
        <p>{{ '☆' }}</p>
    @elseif (取得したいデータ == 2)
        <p>{{ '☆☆' }}</p>
    @elseif (取得したいデータ == 3)
        <p>{{ '☆☆☆' }}</p>
    @elseif (取得したいデータ == 4)
        <p>{{ '☆☆☆☆' }}</p>
    @elseif (取得したいデータ == 5)
        <p>{{ '☆☆☆☆☆' }}</p>
    @endif

viewの記述(switch文を使用する場合)

detail.blade.php
@switch (取得したいデータ)
    @case (1)
        <p>{{ '☆' }}</p>
        @break
    @case (2)
        <p>{{ '☆☆' }}</p>
        @break
    @case (3)
        <p>{{ '☆☆☆' }}</p>
        @break
    @case (4)
       <p>{{ '☆☆☆☆' }}</p>
        @break
    @case (5)
        <p>{{ '☆☆☆☆☆' }}</p>
        @break
@endswitch

viewの記述(1行で済ませたい場合)

detail.blade.php
{{ config('score')[取得したいデータ] }}

参考

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

Laravel Homestead環境のMySQLにホストOSのSequel Proから接続できない場合

環境

  • Vagrant 2.2.7
  • Laravel Homestead 9.2.0
  • PHP 7.4.1
  • Laravel Framework 6.14.0
  • MySQL 5.7.28
  • Sequel Pro 1.1.2

結論

rootユーザだと接続できない設定になっているようです。
homesteadユーザを使いましょう。

Sequel Pro 接続情報例

項目 備考
ホスト homestead.test or 192.168.10.10 Homestead.yamlのip
ユーザ名 homestead .envのDB_USERNAME
パスワード secret .envのDB_PASSWORD
データベース homestead .envのDB_DATABASE

根拠

homesteadは%指定なのでホストマシンからのアクセスが許可されていますが、rootには同様の設定が無いため弾かれているものだと思われます。
0.0.0.0に関しては私は詳しくないのでよく分かりません。コメントにて情報をいただけると助かります。

mysql> select user,host from mysql.user;
+------------------+-----------+
| user             | host      |
+------------------+-----------+
| homestead        | %         |
| homestead        | 0.0.0.0   |
| root             | 0.0.0.0   |
| debian-sys-maint | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| root             | localhost |
+------------------+-----------+
7 rows in set (0.00 sec)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

そろそろaws初めてみよか#5~Cloud9環境での実行~

はじめに

awsと戯れる会も第5回目(^^♪
Cloud9環境でちゃんと開発できるようCloud9のインスタンスにもlaravel環境をセットアップしましたが
肝心のlaravel実行まではできませんでした。
今回はこの肝心の部分の記事になります♪

以前の記事はこちらから
- そろそろaws初めてみよか~まずは触れてみた~
- そろそろaws初めてみよか#2~CodeStarによるコード修正からDeployまで~
- そろそろaws初めてみよか#3~RDSとの接続~
- そろそろaws初めてみよか#4~Cloud9環境の整備~

Cloud9のビルトインサーバでの起動

Run>Run with>PHP (build-in web server)を選択します。

01.png

下ペインに現れる[New]タブの[CWD]をクリックし、ドキュメントルートphp-laravel/publicを選択します。
02.png

上のメニューからPreviewをクリックしブラウザを表示させます。
Oopsとか表示されますが、ポート番号があっていないためなので気にしない気にしない。
03.png

PHP (build-in web server)は下ペインのメッセージにある通り
Listening on http://0.0.0.0:8080
となっていますので、プレビューのURL欄をクリックし「:8080」を追加します。

04.png
04.5.png

それっぽい画面が出てきましたが…スクリプトも画像も読み込まれていません。
Chromeの別タブで同URLを表示させ、ソース表示すると判りますが
ページのURLはhttpsなのに対し、リソースのパスがすべてhttpとなっていることが原因でした。

04.6.png
04.7.png

laravelでassetとかのパスをhttpsで出力する

assetとかで指定したアドレスがことごとくhttpになっているのでhttpsになるようlaravel側で対応します。

具体的には此方の記事を参考にさせて頂きました。
Laravel5.3でSSL通信を強制する

修正したのはAppServiceProviderのboot()の定義となります。
なお本番環境にデプロイした際はhttpだったのでここではapp.envがlocal,stagingの場合のみhttpsにするとしています。
本来の商用環境ではELBも入りhttpsになると思うのでその際は修正が必要となります。

app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

修正後

app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //

        if (config('app.env') === 'local' || config('app.env') === 'staging') {
            \URL::forceSchema('https');
        }
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

これで確認するとこんな感じで正常に表示されます。
どうやらIDE内のブラウザではsvgが動かないっぽいので、動確するなら別タブで開いた方がよさそうですね!

05.png

06.png

07.png

これで本当の意味で開発環境を作ることができました!

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

Laradockでの環境構築からSeleniumでお手軽スクレイピング

概要

タイトル通りです。

対象者

スクレイピングするのに、Seleniumで 妥協していいや やりたいんだ!って人。

Laradockとは

Laravel + Dockerです。

Laravelとは

Laravelです。

Dockerとは

Dockerです。

Seleniumとは

ウェブアプリケーションの自動化を目的としたブラウザ用のテストツール群です。
しかしながら本記事で解説するようにスクレイピングを行うにあたっても利用できます。
指定したウェブサイトへアクセスし、指定したページに遷移し、指定した情報を読み取ってくるなどの動きが出来ます。
あくまでテスト用ツールなので、スクレイピングを主目的とするならイケてるPythonとかのそういうツールを使った方がいいです。
Selenium最高です。Selenium使いましょう。

今回スクレイピングで利用するツールの概要

  • Selenium Server
    クライアントとドライバーの中継役として働くサーバーです。Javaのコードで実装されています。
  • Chrome Driver
    ブラウザ操作に関する命令を仲介してくれます。 Chromeじゃなくてもいいですが、今回はChromeを使用します。他にもFirefox、IEなどがあります。
  • php-webdriver
    Chrome Driverを動かすためのライブラリ。PHPでは公式にドライバーを動かせるツールが無い為、Facebookが作ったらしいです。

Seleniumを使用したスクレイピングのしくみ

ざっくり説明すると、
プログラム => PHP WeDriver => Selenium Server => Chrome Driver => Chrome => スクレイピング対象Webサイト

みたいな感じですかね!知らんけど。

環境構築

LaravelとDocker

LaravelとDockerの環境構築については私の書いたズボラなこちらの記事を参考にしてください。
https://qiita.com/heiheiyoyo/items/0ff035d018a1ce268c69

Selenium

LaravelとDockerの環境構築はできたと思うので、早速SeleniumのコンテナをDockerで立ち上げましょう!

Seleniumコンテナの立ち上げについて必要な記述はLaradockのdocker-compose.ymlとDockerfileに既に記載されてますので、以下のコマンドを叩くだけでOKです。

$ docker-compose up -d selenium

立ち上がったか確認しましょう。
以下のようにSeleniumコンテナが立ち上がっていればOKです。

$ docker ps
d05e612e2baf        laradock_selenium    "/opt/bin/entry_poin…"   3 minutes ago       Up 3 minutes        0.0.0.0:4444->4444/tcp                           laradock_selenium_1
以下省略...

ちなみLaradock内のSeleniumのDockerfileを見てみると、以下のようになっており、デフォルトでベースのイメージがselenium/standalone-chromeにとされているので、今回の環境構築の手間が省けました。

FROM selenium/standalone-chrome

LABEL maintainer="Edmund Luong <edmundvmluong@gmail.com>"

EXPOSE 4444

php-webdriver

php-webdriverはまだインストールされていないので、ここで準備しておきます。
プロジェクト直下にあるcomposer.jsonというファイルに追記していきます。
この、composer.jsonというのはインストールしたいパッケージを記述しておき、後からコマンドを叩いた時に、まとめてインストールする為のファイルです。json形式で記述します。
ちなみに、require-devというのは本番に必要のない開発用のパッケージを記述する場所です。
本番でも必要な場合はrequireに記述しましょう。
今回はとりあえず、require-devに記述しておきます。
バージョンの書き方など詳しく知りたければ調べてください。
以下のリンクが参考になります。
Access Japan
https://access-jp.co.jp/blogs/development/256

とりあえず今回は最新版でインストールします。

追記前

"require-dev": {
        "facade/ignition": "^1.4",
        "fzaninotto/faker": "^1.4",
        "mockery/mockery": "^1.0",
        "nunomaduro/collision": "^3.0",
        "phpunit/phpunit": "^8.0"
    },

追記後

"require-dev": {
        "facade/ignition": "^1.4",
        "fzaninotto/faker": "^1.4",
        "mockery/mockery": "^1.0",
        "nunomaduro/collision": "^3.0",
        "phpunit/phpunit": "^8.0",
        "php-webdriver/webdriver": "*"
    },

composer updateコマンドを実行します。

composer updateはcomposer.jsonの情報を元に各ファイルを最新版にアップデートするらしいです。
これでプロジェクト内のvenderディレクトリにphp-webdriverというディレクトリが出来たと思います。
この中に実際にブラウザを操作するためのファイルがいろいろと入っています。

この中にChromeDriver.phpに定義されているChromeDriverクラスというものがドライバーの起動等を担ってくれるのですが、今回はコイツを使わず、継承元であるRemoteWebDriverというクラスを直接使っていきます。このRemoteWebDriverクラスにはスクレイピングに必要な処理(どのURLにアクセスするとか、どのページのどの要素を読み込むか等々)が色々と定義されています。(正確にはRemoteWebDriverはWebDriverインターフェースを実装しているので、定義自体はインターフェースで行われています。)

$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 1 install, 0 updates, 1 removal
  - Removing facebook/webdriver (1.7.1)
  - Installing php-webdriver/webdriver (1.7.1): Downloading (100%)         
php-webdriver/webdriver suggests installing ext-SimpleXML (For Firefox profile creation)
Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.

ここまでくれば環境構築は終了ですが、最後にプロジェクト内にvendor/autoload.phpのファイルが存在するかをチェックしておいて下さい。なければcomposer install等を実行し、作っておいて下さい。
あとで使いますが、autoload.phpをrequireするだけで、vendor配下のファイルを自動で読み込めるので、便利です。

実装

クローラの作成

さあ実装に入っていきますが、まずはスクレイピングを行うにあたっての本体的な役割にあたるクローラというプログラムを作っていきましょう。

参考

クローラ(Crawler)とは、ウェブ上の文書や画像などを周期的に取得し、自動的にデータベース化するプログラムである。「ボット(Bot)」、「スパイダー」、「ロボット」などとも呼ばれる。(Wikipedia)

今回は手軽に実装する為、スクレイピングの開始から終了までを一つのファイルにまとめたものを作っていきます。(Laravelのコマンドクラスを使います。)

本格的にクローラを運用するなら、クローラの構成は、クローリングの処理はコマンドクラスとジョブクラスに分け、非同期処理を行う。さらに他クラスでDBの永続化処理を行うというような実装ができますが、それはまた別の機会にでもやりたいと思います。(やらんけど)

コマンドクラスの作成

以下のコマンドでコマンドクラスを作りましょう。「php artisan hogehoge(例)」 の「hogehoge」に当たる部分を自作していきます。自作したコマンドを叩けば、クローラの処理が実行されるという感じにしていきたいと思います。

デフォルトでapp/Console/Commands/に作成されます。

$ php artisan make:command SeleniumTestCommand
Console command created successfully.

作成されたコマンドクラスは以下のようになっていると思います。

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class SeleniumTestCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:name';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
    }
}

このコマンドクラスを書き換えていきましょう。

ソースコード

先ほど作成したコマンドクラスを適当に以下のように書き換えて下さい。

<?php

namespace App\Console\Commands;

require base_path(). '/vendor/autoload.php';

use Illuminate\Console\Command;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\WebDriverExpectedCondition;

class SeleniumTestCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'scrape:selenium-test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Seleniumでスクレイピングをするよ';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // クロームの機能を管理するクラスのインスタンス化
        $options = new ChromeOptions();
        // クローム起動時のオプション格納
        $options->addArguments([
            '--no-sandbox',
            '--headless'
        ]);

        // Chromeブラウザを起動
        $caps = DesiredCapabilities::chrome();
        $caps->setCapability(ChromeOptions::CAPABILITY, $options);
        // ブラウザを実行するプラットフォームを指定。クロームとのセッションがスムーズになる??
        $caps->setPlatform("LINUX");

        // これはSelenium Serverの置いてあるURLなのかな
        $host = 'http://localhost:4444/wd/hub';

        try {
            // なんかよく起動できずに落ちたので、retry()でくくる
            $driver = retry(3, function () use ($host, $caps) {
                // chrome ドライバーの起動、ウイーーーーーーーーーーーン
                return RemoteWebDriver::create($host, $caps, 60000, 60000);
            }, 1000);


            // Y◯hoo!さんのニュースサイトに潜入します
            $driver->get('https://news.yahoo.co.jp');

            dump($driver->getCurrentUrl());

            // ページタイトル「Yahoo!ニュース」が現れるまで待ちます
            $driver->wait()->until(
                WebDriverExpectedCondition::titleIs('Yahoo!ニュース')
            );

            // トップページのトピックをリンクを取得していきます
            $topics_counts = count($driver->findElement(WebDriverBy::className('topicsList_main'))
                                          ->findElements(WebDriverBy::className('topicsListItem')));

            // リンク集
            $links = [];

            for ($i=0; $i <= $topics_counts -1; $i++) {
                $links[] = $driver->findElement(WebDriverBy::className('topicsList_main'))
                                  ->findElements(WebDriverBy::className('topicsListItem'))[$i]
                                  ->findElement(WebDriverBy::tagName('a'))
                                  ->getAttribute('href');
            }

            // リンクの数だけアクセス
            foreach ($links as $link) {

                // リンクが取得できているか
                dump($link);

                // URLにアクセス
                $driver->get($link);

                // ページタイトルに「Yahoo!ニュース」が含まれるものが現れるまで待ちます
                $driver->wait()->until(WebDriverExpectedCondition::titleContains('Yahoo!ニュース'));

                // 記事のタイトルをクローリングします
                $article_title = $driver->findElement(WebDriverBy::className('pickupMain_articleTitle'))
                                        ->getText();

                // 記事のタイトルが取得できているか
                dump($article_title);
            }

            // 処理終了
            return;
        } catch (\Exception $e) {
            echo 'エラーによりスクレイピングが失敗しました。ERROR MESSAGE : '.$e->getErrorMessage().' TRACE : '.$e->getTraceAsString();
        } finally {
            $driver->quit();
        }
    }
}

実行

以下のコマンドで実行しましょう。

$ php artisan scrape:selenium-test

うまくいけば、ターミナル常にdumpの出力がされて

サイトトップページURL
記事のページのURL
記事のタイトル
記事のページのURL
記事のタイトル
記事のページのURL
記事のタイトル
...

みたいになると思います。

うまくいかなければ、、、
てへぺろ。

解説

※後半から畳み掛けるように雑になると思います。

ChromeOptionsクラスのインスタンス化

ChromeOptionsクラスはChromeの機能を管理するクラスです。

$options = new ChromeOptions();

Chrome起動時に渡すコマンド引数の設定

以下のように指定します。headlessはヘッドレスモードで起動する設定で、no-sandboxはセキュリティを下げ、スリルを味わってスクレイピングしたい人向けの設定です。
addArguments()でChromeOptionsクラスのクラス変数argumentsにarrayで引数を渡しています。
argumentsはChromeの起動時に適用されます。

$options->addArguments([
            '--no-sandbox',
            '--headless'
        ]);

参考オプション一覧

  • user-data-dir... ユーザープロファイルの設定。 Chromeは複数のユーザーを使い分けられるらしいので、ユーザー毎にブックマーク、履歴、パスワードなどをプロファイル毎に管理できるのだと思います。
  • --proxy-server... プロキシサーバーの設定。 プロキシサーバーはクライアントとWebサイトの中継役を行います。セキュリティの向上などが見込まれます。
  • --headless... ヘッドレスモード。ブラウザのUIなしで起動できます。
  • --no-sandbox... サンドボックスの外でプロセスを動作させる。
  • window-size... 画面幅指定。
  • --start-maximized... 画面幅を最大化して起動します。
  • --user-agent... 他のブラウザや端末に偽装できます。(なりすませます。)
  • --incognito... シークレットモードで起動。履歴とかが残らない。アダルトサイトのスクレイピングとかにいいんじゃないっすかね。(誰がやんねん)
  • --single-process... シングルプロセスで起動します。通常はタブ、サイト毎のマルチプロセスで起動するっぽいのですが、場合によってはメモリの使用量とか負担になるので使用するといいかもしれません。
  • --disable-javascript... JavaScriptを無効にします。
  • --disable-popup-blocking... ポップアップブロックを無効にします。コード内でアラート等に対応する必要がなくなりそうなので、便利ですね。
  • --enable-logging... ログ出力を有効化します。ファイルはChrome\Application\chrome_debug.logで作成されるみたいです。
  • --log-level... ログレベルを設定できます。
  • --dump-histograms-on-exit... 終了時に各種統計情報をログファイルへ出力するという設定です。

オプションについては以下のサイトがよくまとめられており、参考になります。
起動オプション - Google Chrome まとめWiki
http://chrome.half-moon.org/43.html#y3a4f50e

その他Chromeの設定

今回は設定していませんが、例えば何かしらのファイルをスクレイピングで取得したいとします。
その場合はダウンロードしたファイルの保存先を以下のように設定します。download.default_directoryはデフォルトのダウンロードディレクトリを指定するオプションです。
ちなみにsetExperimentalOption()はChromeOptions APIを介してまだ公開されていないChromeDriverオプションを試す為に使用します。(実験的なオプションを指定する的な。)
prefは起動時の引数とは異なり、起動後?の設定画面の項目のことを指しています。

$options->setExperimentalOption('prefs', [
            'download.default_directory' => "任意のパス",
        ]);

設定の反映〜ドライバー立ち上げ

まずは、ドライバーを起動させる際の設定をしています。

// Chromeブラウザを起動
$caps = DesiredCapabilities::chrome();
$caps->setCapability(ChromeOptions::CAPABILITY, $options);
// ブラウザを実行するプラットフォームを指定。クロームとのセッションがスムーズになる??
$caps->setPlatform("LINUX");

// これはSelenium Serverの置いてあるURLなのかな
$host = 'http://localhost:4444/wd/hub';

次にドライバーを起動させます。
このタイミングで設定情報を渡してあげて下さい。
ちなみに原因不明ですが、Curl error thrown for http POST to...みたいなエラーを吐き捨てられることがよくあったので、リトライでくくっています。(要らないかも)

// なんかよく起動できずに落ちたので、retry()でくくる
$driver = retry(3, function () use ($host, $caps) {
    // chrome ドライバーの起動、ウイーーーーーーーーーーーン
    return RemoteWebDriver::create($host, $caps, 60000, 60000);
}, 1000);

いざ、クローリング開始

ドライバーの立ち上げに成功したら、Webサイトへアクセスします。
今回は天下のY◯hoo!さんのニュースサイトにお邪魔しようと思います。
トップページにアクセスして話題になっているトピックのページに遷移し、記事のタイトルを読み取ってくるという流れでいきます。

// Y◯hoo!さんのニュースサイトに潜入します
$driver->get('https://news.yahoo.co.jp');

// ページタイトル「Yahoo!ニュース」が現れるまで待ちます
$driver->wait()->until(
    WebDriverExpectedCondition::titleIs('Yahoo!ニュース')
);

トップページの左上部あたりに注目のニュース?的なトピックがあるので、その数をカウントしています。

// トップページのトピックをリンクを取得していきます
$topics_counts = count($driver->findElement(WebDriverBy::className('topicsList_main'))
                              ->findElements(WebDriverBy::className('topicsListItem')));

classNameの名前を指定し、トピックの数だけ該当するaタグのhrefを配列に格納していきます。

// リンク集
$links = [];

for ($i=0; $i <= $topics_counts -1; $i++) {

$links[] = $driver->findElement(WebDriverBy::className('topicsList_main'))
                  ->findElements(WebDriverBy::className('topicsListItem'))[$i]
                  ->findElement(WebDriverBy::tagName('a'))
                  ->getAttribute('href');
}

リンクが集まれば、リンクの数だけそのページにアクセスしていきましょう。
さらにリンク先に記事のタイトル文章が記載されているので、それを読み取ってきます。

// リンクの数だけアクセス
foreach ($links as $link) {

// リンクが取得できているか
dump($link);

// URLにアクセス
$driver->get($link);

// ページタイトルに「Yahoo!ニュース」が含まれるものが現れるまで待ちます
$driver->wait()->until(WebDriverExpectedCondition::titleContains('Yahoo!ニュース'));

// 記事のタイトルをクローリングします
$article_title = $driver->findElement(WebDriverBy::className('pickupMain_articleTitle'))
                        ->getText();

// 記事のタイトルが取得できているか
dump($article_title);
}

大部分の処理はこれで終了です。

補足

ChromeDriverを起動させましたが、場合によっては処理が終了したにも関わらず、プロセスが残り続けることがあるみたいです。

なんか嫌なので、quit()で終了させるようにしましょう。
finallyの中に組み込めば必ず実行されると思います。

} finally {
    $driver->quit();
}

はい!
ということでお手軽にスクレイピングができました!
現場からは以上です!

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

docker-composeでLaravel環境構築

はじめに

dockerによってLaravelの環境構築を行います。laradockは使いません。
以前はlaradockを使っていましたが、
・プロジェクトが必要以上に大きくなる
・dockerの知識がほとんどなくても環境構築できでしまう
これらの点からlaradockを使わない方法を試していきます。

laradockはとりあえずdockerでLaravelを立ち上げたい方、知識が全くない方は使うとよいかもしれません。

以前にlaradockによるlaravelの環境構築の記事を書きましたので、laradockを使いたい方はこちらを→https://qiita.com/rope19181/items/da31dc2cd6097315fa10

環境・仕様

・nginx上でPHP実行環境を構築し、Laravel新規プロジェクト作成。
・mysqlとwebGUIとしてphpmyadminも使えるようにします。

環境、仕様は以下の通りです。
Docker version 19.03.5
docker-compose version 1.24.1
php 7.2-fpm
mysql 5.7

構成

最終的にこのような構成となります。

project
├ docker
│  ├ db
│  │ ├ data
│  │ ├ my.conf
│  │ └ sql
│  │
│  ├ nginx
│  │  └ default.conf
│  │  
│  └ php
│   ├ Dockerfile
│   └ php.ini  
├ myapp
└ docker-compose.yml

今回はprojectをルートディレクトリとしています。

./myappはlaravelのプロジェクトを置くディレクトリとなります。

docker-compose.ymlの作成

docker-composeでは複数のコンテナを管理、構築するためにdocker-compose.ymlに各コンテナの環境設定を定義します。

docker-compose.yml
version: '3'

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
      - ./myapp/:/var/www

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    volumes:
    - ./myapp/:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:5.7
    container_name: db-host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=db-host
      - PMA_USER=docker
      - PMA_PASSWORD=docker
    links:
      - db
    ports:
      - 8080:80
    volumes:
      - /sessions

各項目について簡単に説明します。
詳しくは公式リファレンスを見てみましょう。https://docs.docker.com/compose/compose-file/

image

ローカルやリモートにあるイメージを指定します。ローカルにない場合リモートからpullされます。

今回はnginx、mysql、phpmyadminはローカルのイメージを指定しています。

build

イメージをbuildする際に参照するファイルを指定します。
要はイメージを構築する場合はこちらを使うわけです。またbuildとimageを両方指定することはできません。

今回はphpコンテナの構築でDockerfileを使うため、そのディレクトリのパスを指定しています。

volumes

ボリュームとしてマウントするパスを指定します。ホスト:コンテナまたアクセスモードを読み取り専用する場合ホスト:コンテナ:roとします。

今回はアクセスモードを指定しないためrwとなり、書き込みもできるボリュームです。

ports

公開(expose)するポートをします。ホスト:コンテナとします。

ポートが被る場合はここを変更します。

links

コンテナにリンクさせるサービス名を指定します。
注)コンテナ名(container_name)ではなくサービス名

今回はphpmyadminのコンテナにてdb-hostコンテナのサービス名であるdbを指定しています。

phpのDockerfileの作成

phpコンテナではLaravelの実行のためにcomposerのインストールします。
公式(https://getcomposer.org/download/) から下の部分を#Composer installのところに貼り付けます。

スクリーンショット 2020-02-10 18.55.21.png

Dockerfile
FROM php:7.2-fpm
COPY php.ini /usr/local/etc/php/

RUN apt-get update \
  && apt-get install -y zlib1g-dev mariadb-client \
  && docker-php-ext-install zip pdo_mysql

#Composer install
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'c5b9b6d368201a9db6f74e2611495f369991b72d9c8cbd3ffbc63edff210eb73d46ffbfce88669ad33695ef77dc76976') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

RUN composer global require "laravel/installer"

PHP設定ファイルの作成

docker/php/にphp.iniを作成します。

php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

nginxの設定ファイルの作成

docker/nginxにdefault.confを作成します。

default.conf
server {
  listen 80;
    index index.php index.html;
    root /var/www/public;

  location / {
    root /var/www/public;
    index  index.html index.php;
    }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
 }

dockerの起動

下記コマンドでdockerを起動させます。初回は結構時間がかかります。
docker-composeではupによってイメージの構築、コンテナの起動を行いますが、初回はキャッシュがないため--buildをつけます。-dオプションによってバックグラウンドで起動させます。

$ docker-compose up -d --build

laravelプロジェクトの作成

まずはphpコンテナに入ります。コンテナに入る場合はexecコマンドを実行します。

$ docker-compose exec php bash

laravelの新規プロジェクトを作成します。

composer create-project --prefer-dist "laravel/laravel myapp

laravelプロジェクトの環境設定

laravelプロジェクト内の.envやconfig/detabase.phpのデータベースの設定を変更します。
DB名、ユーザ名、パスワードなどを先ほどdocker-compose.ymlに設定した値に変更しましょう。

動作確認

nginx、php

http://localhost にアクセスしlaravelのホームページが表示されればOK。

スクリーンショット 2020-02-11 00.24.57.png

mysql、phpmyadmin

phpコンテナに入り、migrateします。

$ docker-compose exec php bash

$ php artisan migrate

http://localhost:8080 にアクセスし、phpmyadminが立ち上がりDB内に2つのテーブルが作成されていれば成功。

スクリーンショット 2020-02-11 00.23.37.png

最後に

laradockも簡単にできますが、少しの知識があればこちらの方法のほうがシンプルで分かりやすいと思います。

laradockを使いたい方はこちら→https://qiita.com/rope19181/items/da31dc2cd6097315fa10

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

dockerでLaravel環境構築

はじめに

dockerによってLaravelの環境構築を行います。できるだけシンプルな構成を目指します。laradockは使いません。

自分は以前laradockを使っていましたが、
・プロジェクトが必要以上に大きくなる
・dockerの知識がほとんどなくても環境構築できでしまう
これらの点からlaradockを使わない方法を試していきます。

laradockはとりあえずdockerでLaravelを立ち上げたい方、知識が全くない方は使うとよいかもしれません。

以前にlaradockによるlaravelの環境構築の記事を書きましたので、laradockを使いたい方はこちらを→https://qiita.com/rope19181/items/da31dc2cd6097315fa10

環境・仕様

・nginx上でPHP実行環境を構築し、Laravel新規プロジェクト作成。
・mysqlとwebGUIとしてphpmyadminも使えるようにします。

・環境、仕様は以下の通りです。
Docker version 19.03.5
docker-compose version 1.24.1
php 7.2-fpm
mysql 5.7

構成

最終的にこのような構成となります。

project
├ docker
│  ├ db
│  │ ├ data
│  │ ├ my.conf
│  │ └ sql
│  │
│  ├ nginx
│  │  └ default.conf
│  │  
│  └ php
│   ├ Dockerfile
│   └ php.ini  
├ myapp
└ docker-compose.yml

今回はprojectをルートディレクトリとしています。

./myappはlaravelのプロジェクトを置くディレクトリとなります。

docker-compose.ymlの作成

docker-composeでは複数のコンテナを管理、構築するためにdocker-compose.ymlに各コンテナの環境設定を定義します。

docker-compose.yml
version: '3'

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
      - ./myapp/:/var/www

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 80:80
    volumes:
    - ./myapp/:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:5.7
    container_name: db-host
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306

  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    container_name: phpmyadmin
    environment:
      - PMA_ARBITRARY=1
      - PMA_HOST=db-host
      - PMA_USER=docker
      - PMA_PASSWORD=docker
    links:
      - db
    ports:
      - 8080:80
    volumes:
      - /sessions

各項目について簡単に説明します。
詳しくは公式リファレンスを見てみましょう。https://docs.docker.com/compose/compose-file/

image

ローカルやリモートにあるイメージを指定します。ローカルにない場合リモートからpullされます。

今回はnginx、mysql、phpmyadminはリモートのイメージを指定しています。

build

イメージをbuildする際に参照するファイルを指定します。
要はイメージを構築する場合はこちらを使うわけです。またbuildとimageを両方指定することはできません。

今回はphpコンテナの構築でDockerfileを使うため、そのディレクトリのパスを指定しています。

volumes

ボリュームとしてマウントするパスを指定します。ホスト:コンテナまたアクセスモードを読み取り専用する場合ホスト:コンテナ:roとします。

今回はアクセスモードを指定しないためrwとなり、書き込みもできるボリュームです。

ports

公開(expose)するポートをします。ホスト:コンテナとします。

ポートが被る場合はここを変更します。

links

コンテナにリンクさせるサービス名を指定します。
注)コンテナ名(container_name)ではなくサービス名

今回はphpmyadminのコンテナにてdb-hostコンテナのサービス名であるdbを指定しています。

phpのDockerfileの作成

phpコンテナではLaravelの実行のためにcomposerのインストールします。
公式(https://getcomposer.org/download/) から下の部分を#Composer installのところに貼り付けます。

スクリーンショット 2020-02-10 18.55.21.png

Dockerfile
FROM php:7.2-fpm
COPY php.ini /usr/local/etc/php/

RUN apt-get update \
  && apt-get install -y zlib1g-dev mariadb-client \
  && docker-php-ext-install zip pdo_mysql

#Composer install
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'c5b9b6d368201a9db6f74e2611495f369991b72d9c8cbd3ffbc63edff210eb73d46ffbfce88669ad33695ef77dc76976') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1

ENV COMPOSER_HOME /composer

ENV PATH $PATH:/composer/vendor/bin


WORKDIR /var/www

RUN composer global require "laravel/installer"

PHP設定ファイルの作成

docker/php/にphp.iniを作成します。

php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

nginxの設定ファイルの作成

docker/nginxにdefault.confを作成します。

default.conf
server {
  listen 80;
    index index.php index.html;
    root /var/www/public;

  location / {
    root /var/www/public;
    index  index.html index.php;
    }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
 }

dockerの起動

下記コマンドでdockerを起動させます。初回は結構時間がかかります。
docker-composeではupによってイメージの構築、コンテナの起動を行いますが、初回はキャッシュがないため--buildをつけます。-dオプションによってバックグラウンドで起動させます。

$ docker-compose up -d --build

laravelプロジェクトの作成

まずはphpコンテナに入ります。コンテナに入る場合はexecコマンドを実行します。

$ docker-compose exec php bash

laravelの新規プロジェクトを作成します。

composer create-project --prefer-dist "laravel/laravel myapp

laravelプロジェクトの環境設定

laravelプロジェクト内の.envやconfig/detabase.phpのデータベースの設定を変更します。
DB名、ユーザ名、パスワードなどを先ほどdocker-compose.ymlに設定した値に変更しましょう。

動作確認

nginx、php

http://localhost にアクセスしlaravelのホームページが表示されればOK。

スクリーンショット 2020-02-11 00.24.57.png

mysql、phpmyadmin

phpコンテナに入り、migrateします。

$ docker-compose exec php bash

$ php artisan migrate

http://localhost:8080 にアクセスし、phpmyadminが立ち上がりDB内に2つのテーブルが作成されていれば成功。

スクリーンショット 2020-02-11 00.23.37.png

docker-composeコマンド小まとめ

よく使うものをまとめます。

up

コンテナの構築、起動をします。

似たものとしてイメージの構築のみを行うbuild、コンテナの起動のみを行うstartなどがありますが、docker-composeではとりあえずupをしとけばいいと思います。
Dockerfileを更新した時などはbuildしましょう。

$ docker-compose up -d  
$ docker-compose up -d --build #初回の起動などbuildもしたいとき

down

upで作られたものを削除します。downだけだとコンテナとネットワークの削除を行います。オプションによってその範囲を指定します。

$ docker-compose down

コンテナ、イメージ、ボリュームそしてネットワークすべてを削除したい場合は

$ docker-compose down --rmi all --volumes

exec

起動中のコンテナでコマンドを実行

$ docker-compose exec コンテナ名 実行するコマンド

$ docker-compose exec コンテナ名 bash #コンテナに入る場合

最後に

laradockも簡単にできますが、少しの知識があればこちらの方法のほうがシンプルで分かりやすいと思います。

laradockを使いたい方はこちら→https://qiita.com/rope19181/items/da31dc2cd6097315fa10

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

Laravelの「There is no existing directory at "/Users/hoge/workspace/SamplePrpject/storage/logs" 」の解決方法

はじめに

Laravelのconfigファイルを修正後にphp artisan config:cacheを実行したら、表題のエラーが出たのでその際の解決方法を忘備録として残しておきます。

開発環境

言語・FW     バージョン
Laravel 6.14.0
PHP 7.2.26

エラーの内容

UnexpectedValueException

There is no existing directory at "/Users/hoge/workspace/SamplePrpject/storage/logs" and its not buildable: Permission denied

Monolog\Handler\StreamHandler::createDir:171
vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php:171

解決方法

初めにエラーログで指摘されている箇所が存在するか確認

$ cd storage/logs

存在する場合は、logsディレクトリの権限を確認
今回の場合は権限が777になっている

$ ll
drwxrwxrwx 4 user_name staff 128B 2 6 22:39 logs

キャッシュクリアの実行

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

自分の場合はキャッシュクリアを実行したら直りました。

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

そろそろaws初めてみよか#4~Cloud9環境の整備~

はじめに

awsと戯れる会も第4回目(^^♪
Cloud9環境でちゃんと開発できるようCloud9のインスタンスにもlaravel環境をセットアップします。

以前の記事はこちらから
- そろそろaws初めてみよか~まずは触れてみた~
- そろそろaws初めてみよか#2~CodeStarによるコード修正からDeployまで~
- そろそろaws初めてみよか#3~RDSとの接続~

phpのバージョンアップ(5.6->7.3)

Cloud9上のphpは5.6.40
ところが実行環境であるインスタンスのphpは7.3.13
って事でphpのインストールと切り替えを行います。

php73のインストール

ec2-user:~ $ sudo yum install php73 php73-gd php73-json php73-mbstring php73-mysqlnd php73-pdo php73-soap php73-xml
 :

phpの切り替え(5.6->7.3)

ec2-user:~ $ php -v
PHP 5.6.40 (cli) (built: Oct 31 2019 20:35:16) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Xdebug v2.5.5, Copyright (c) 2002-2017, by Derick Rethans
ec2-user:~ $ sudo alternatives --config php

There are 2 programs which provide 'php'.

  Selection    Command
-----------------------------------------------
*+ 1           /usr/bin/php-5.6
   2           /usr/bin/php-7.3

Enter to keep the current selection[+], or type selection number: 2
ec2-user:~ $ php -v
PHP 7.3.13 (cli) (built: Jan 21 2020 19:15:52) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.13, Copyright (c) 1998-2018 Zend Technologies
ec2-user:~ $ 

composerのインストール

次に必要となってくるcomposerのインストールを行います。
公式の手順(https://getcomposer.org/download/)に則って

ec2-user:~ $ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ec2-user:~ $ php -r "if (hash_file('sha384', 'composer-setup.php') === 'c5b9b6d368201a9db6f74e2611495f369991b72d9c8cbd3ffbc63edff210eb73d46ffbfce88669ad33695ef77dc76976') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
Installer verified
ec2-user:~ $ php composer-setup.php
All settings correct for using Composer
Downloading...

Composer (version 1.9.3) successfully installed to: /home/ec2-user/composer.phar
Use it: php composer.phar

ec2-user:~ $ php -r "unlink('composer-setup.php');"
ec2-user:~ $ ls
composer.phar  environment  node_modules  package-lock.json

laravelなどのインストール

プロジェクトフォルダにはcomposer.jsonがありますので、以下のコマンドで必要なモジュールをインストールします。
ちなみにGitからCloneされたソースは~\environmentにあります。

ec2-user:~ $ 
ec2-user:~ $ cd environment/
ec2-user:~/environment $ cd php-laravel
ec2-user:~/environment/php-laravel (master) $ ls
app          artisan    buildspec.yml  composer.lock  database     index.php     phpunit.xml  README.md  routes   server.php  template-configuration.json  tests
appspec.yml  bootstrap  composer.json  config         gulpfile.js  package.json  public       resources  scripts  storage     template.yml

ec2-user:~/environment/php-laravel (master) $ ~/composer.phar install
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Package operations: 63 installs, 0 updates, 0 removals
  - Installing kylekatarnls/update-helper (1.2.0): Downloading (100%)         
  - Installing jakub-onderka/php-console-color (v0.2): Downloading (100%)         
  - Installing symfony/polyfill-ctype (v1.12.0): Downloading (100%)         
  - Installing vlucas/phpdotenv (v2.6.1): Downloading (100%)         
  - Installing symfony/polyfill-mbstring (v1.12.0): Downloading (100%)         
  - Installing symfony/var-dumper (v3.1.10): Downloading (100%)         
  - Installing symfony/translation (v3.1.10): Downloading (100%)         
  - Installing symfony/routing (v3.1.10): Downloading (100%)         
  - Installing symfony/process (v3.1.10): Downloading (100%)         
  - Installing symfony/http-foundation (v3.1.10): Downloading (100%)         
  - Installing symfony/event-dispatcher (v3.4.30): Downloading (100%)         
  - Installing psr/log (1.1.0): Downloading (100%)         
  - Installing symfony/debug (v3.1.10): Downloading (100%)         
  - Installing symfony/http-kernel (v3.1.10): Downloading (100%)         
  - Installing symfony/finder (v3.1.10): Downloading (100%)         
  - Installing symfony/console (v3.1.10): Downloading (100%)         
  - Installing swiftmailer/swiftmailer (v5.4.12): Downloading (100%)         
  - Installing paragonie/random_compat (v2.0.18): Downloading (100%)         
  - Installing ramsey/uuid (3.8.0): Downloading (100%)         
  - Installing nikic/php-parser (v3.1.5): Downloading (100%)         
  - Installing jakub-onderka/php-console-highlighter (v0.3.2): Downloading (100%)         
  - Installing dnoegel/php-xdg-base-dir (0.1): Downloading (100%)         
  - Installing psy/psysh (v0.8.18): Downloading (100%)         
  - Installing nesbot/carbon (1.39.0): Downloading (100%)         
  - Installing mtdowling/cron-expression (v1.2.1): Downloading (100%)         
  - Installing monolog/monolog (1.24.0): Downloading (100%)         
  - Installing league/flysystem (1.0.53): Downloading (100%)         
  - Installing symfony/polyfill-util (v1.12.0): Downloading (100%)         
  - Installing symfony/polyfill-php56 (v1.12.0): Downloading (100%)         
  - Installing jeremeamia/superclosure (2.4.0): Downloading (100%)         
  - Installing doctrine/inflector (v1.3.0): Downloading (100%)         
  - Installing classpreloader/classpreloader (3.2.0): Downloading (100%)         
  - Installing laravel/framework (v5.3.31): Downloading (100%)         
  - Installing fzaninotto/faker (v1.8.0): Downloading (100%)         
  - Installing hamcrest/hamcrest-php (v1.2.2): Downloading (100%)         
  - Installing mockery/mockery (0.9.11): Downloading (100%)         
  - Installing webmozart/assert (1.4.0): Downloading (100%)         
  - Installing phpdocumentor/reflection-common (1.0.1): Downloading (100%)         
  - Installing phpdocumentor/type-resolver (0.4.0): Downloading (100%)         
  - Installing phpdocumentor/reflection-docblock (4.3.1): Downloading (100%)         
  - Installing phpunit/php-token-stream (2.0.2): Downloading (100%)         
  - Installing symfony/yaml (v3.3.18): Downloading (100%)         
  - Installing sebastian/version (2.0.1): Downloading (100%)         
  - Installing sebastian/resource-operations (1.0.0): Downloading (100%)         
  - Installing sebastian/recursion-context (2.0.0): Downloading (100%)         
  - Installing sebastian/object-enumerator (2.0.1): Downloading (100%)         
  - Installing sebastian/global-state (1.1.1): Downloading (100%)         
  - Installing sebastian/exporter (2.0.0): Downloading (100%)         
  - Installing sebastian/environment (2.0.0): Downloading (100%)         
  - Installing sebastian/diff (1.4.3): Downloading (100%)         
  - Installing sebastian/comparator (1.2.4): Downloading (100%)         
  - Installing phpunit/php-text-template (1.2.1): Downloading (100%)         
  - Installing doctrine/instantiator (1.2.0): Downloading (100%)         
  - Installing phpunit/phpunit-mock-objects (3.4.4): Downloading (100%)         
  - Installing phpunit/php-timer (1.0.9): Downloading (100%)         
  - Installing phpunit/php-file-iterator (1.4.5): Downloading (100%)         
  - Installing sebastian/code-unit-reverse-lookup (1.0.1): Downloading (100%)         
  - Installing phpunit/php-code-coverage (4.0.8): Downloading (100%)         
  - Installing phpspec/prophecy (1.8.1): Downloading (100%)         
  - Installing myclabs/deep-copy (1.9.3): Downloading (100%)         
  - Installing phpunit/phpunit (5.7.27): Downloading (100%)         
  - Installing symfony/css-selector (v3.1.10): Downloading (100%)         
  - Installing symfony/dom-crawler (v3.1.10): Downloading (100%)         
symfony/var-dumper suggests installing ext-symfony_debug
symfony/translation suggests installing symfony/config
symfony/routing suggests installing doctrine/annotations (For using the annotation loader)
symfony/routing suggests installing symfony/config (For using the all-in-one router or any loader)
symfony/routing suggests installing symfony/dependency-injection (For loading routes from a service)
symfony/routing suggests installing symfony/expression-language (For using expression matching)
symfony/event-dispatcher suggests installing symfony/dependency-injection
symfony/http-kernel suggests installing symfony/browser-kit
symfony/http-kernel suggests installing symfony/class-loader
symfony/http-kernel suggests installing symfony/config
symfony/http-kernel suggests installing symfony/dependency-injection
paragonie/random_compat suggests installing ext-libsodium (Provides a modern crypto API that can be used to generate random bytes.)
ramsey/uuid suggests installing ext-libsodium (Provides the PECL libsodium extension for use with the SodiumRandomGenerator)
ramsey/uuid suggests installing ext-uuid (Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator)
ramsey/uuid suggests installing ircmaxell/random-lib (Provides RandomLib for use with the RandomLibAdapter)
ramsey/uuid suggests installing moontoast/math (Provides support for converting UUID to 128-bit integer (in string form).)
ramsey/uuid suggests installing ramsey/uuid-console (A console application for generating UUIDs with ramsey/uuid)
ramsey/uuid suggests installing ramsey/uuid-doctrine (Allows the use of Ramsey\Uuid\Uuid as Doctrine field type.)
psy/psysh suggests installing ext-pdo-sqlite (The doc command requires SQLite to work.)
psy/psysh suggests installing hoa/console (A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit.)
monolog/monolog suggests installing aws/aws-sdk-php (Allow sending log messages to AWS services like DynamoDB)
monolog/monolog suggests installing doctrine/couchdb (Allow sending log messages to a CouchDB server)
monolog/monolog suggests installing ext-amqp (Allow sending log messages to an AMQP server (1.0+ required))
monolog/monolog suggests installing ext-mongo (Allow sending log messages to a MongoDB server)
monolog/monolog suggests installing graylog2/gelf-php (Allow sending log messages to a GrayLog2 server)
monolog/monolog suggests installing mongodb/mongodb (Allow sending log messages to a MongoDB server via PHP Driver)
monolog/monolog suggests installing php-amqplib/php-amqplib (Allow sending log messages to an AMQP server using php-amqplib)
monolog/monolog suggests installing php-console/php-console (Allow sending log messages to Google Chrome)
monolog/monolog suggests installing rollbar/rollbar (Allow sending log messages to Rollbar)
monolog/monolog suggests installing ruflin/elastica (Allow sending log messages to an Elastic Search server)
monolog/monolog suggests installing sentry/sentry (Allow sending log messages to a Sentry server)
league/flysystem suggests installing league/flysystem-aws-s3-v2 (Allows you to use S3 storage with AWS SDK v2)
league/flysystem suggests installing league/flysystem-aws-s3-v3 (Allows you to use S3 storage with AWS SDK v3)
league/flysystem suggests installing league/flysystem-azure (Allows you to use Windows Azure Blob storage)
league/flysystem suggests installing league/flysystem-cached-adapter (Flysystem adapter decorator for metadata caching)
league/flysystem suggests installing league/flysystem-eventable-filesystem (Allows you to use EventableFilesystem)
league/flysystem suggests installing league/flysystem-rackspace (Allows you to use Rackspace Cloud Files)
league/flysystem suggests installing league/flysystem-sftp (Allows you to use SFTP server storage via phpseclib)
league/flysystem suggests installing league/flysystem-webdav (Allows you to use WebDAV storage)
league/flysystem suggests installing league/flysystem-ziparchive (Allows you to use ZipArchive adapter)
league/flysystem suggests installing spatie/flysystem-dropbox (Allows you to use Dropbox storage)
league/flysystem suggests installing srmklive/flysystem-dropbox-v2 (Allows you to use Dropbox storage for PHP 5 applications)
laravel/framework suggests installing aws/aws-sdk-php (Required to use the SQS queue driver and SES mail driver (~3.0).)
laravel/framework suggests installing doctrine/dbal (Required to rename columns and drop SQLite columns (~2.4).)
laravel/framework suggests installing guzzlehttp/guzzle (Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~5.3|~6.0).)
laravel/framework suggests installing league/flysystem-aws-s3-v3 (Required to use the Flysystem S3 driver (~1.0).)
laravel/framework suggests installing league/flysystem-rackspace (Required to use the Flysystem Rackspace driver (~1.0).)
laravel/framework suggests installing pda/pheanstalk (Required to use the beanstalk queue driver (~3.0).)
laravel/framework suggests installing predis/predis (Required to use the redis cache and queue drivers (~1.0).)
laravel/framework suggests installing pusher/pusher-php-server (Required to use the Pusher broadcast driver (~2.0).)
laravel/framework suggests installing symfony/psr-http-message-bridge (Required to use psr7 bridging features (0.2.*).)
sebastian/global-state suggests installing ext-uopz (*)
phpunit/php-code-coverage suggests installing ext-xdebug (^2.5.1)
phpunit/phpunit suggests installing ext-xdebug (*)
phpunit/phpunit suggests installing phpunit/php-invoker (~1.1)
Package phpunit/phpunit-mock-objects is abandoned, you should avoid using it. No replacement was suggested.
Generating autoload files
Carbon 1 is deprecated, see how to migrate to Carbon 2.
https://carbon.nesbot.com/docs/#api-carbon-2
    You can run './vendor/bin/upgrade-carbon' to get help in updating carbon and other frameworks and libraries that depend on it.
> Illuminate\Foundation\ComposerScripts::postInstall
> php artisan optimize
Generating optimized class loader
Compiling common classes
ec2-user:~/environment/php-laravel (master) $ 

.envの準備

開発用に.envを作成します。
コマンドでも良いのですがせっかくのIDEですので.env.exampleをコピー&ペーストして.envを作成
以下の部分を書き換えました。

DB_CONNECTION=mysql
DB_HOST=laravel-db.culgyynq9ap1.us-east-2.rds.amazonaws.com
DB_PORT=3306
DB_DATABASE=laravel_dev
DB_USERNAME=admin
DB_PASSWORD=***********

DBはインスタンスは本番と同様でデータベースを分ける想定です。
インスタンスから分けたい場合は、RDSで新たにDBを作成しセキュリティグループの設定を行ってください。
参考)そろそろaws初めてみよか#3~RDSとの接続~

開発用データベースの作成

例によってインスタンスにはmysqlがインストールされていませんのでまずはインストールします。

ec2-user:~/environment/php-laravel (master) $ sudo yum install -y mysql
Loaded plugins: priorities, update-motd, upgrade-helper
amzn-main                                                                                                                                                                                                                     | 2.1 kB  00:00:00     
amzn-updates                                                                                                                                                                                                                  | 2.5 kB  00:00:00     
1073 packages excluded due to repository priority protections
Resolving Dependencies
--> Running transaction check
---> Package mysql.noarch 0:5.5-1.6.amzn1 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

=====================================================================================================================================================================================================================================================
 Package                                                 Arch                                                     Version                                                          Repository                                                   Size
=====================================================================================================================================================================================================================================================
Installing:
 mysql                                                   noarch                                                   5.5-1.6.amzn1                                                    amzn-main                                                   2.7 k

Transaction Summary
=====================================================================================================================================================================================================================================================
Install  1 Package

Total download size: 2.7 k
Installed size: 0  
Downloading packages:
mysql-5.5-1.6.amzn1.noarch.rpm                                                                                                                                                                                                | 2.7 kB  00:00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : mysql-5.5-1.6.amzn1.noarch                                                                                                                                                                                                        1/1 
  Verifying  : mysql-5.5-1.6.amzn1.noarch                                                                                                                                                                                                        1/1 

Installed:
  mysql.noarch 0:5.5-1.6.amzn1                                                                                                                                                                                                                       

Complete!

次にデータベースに接続し、データベースを作成します。
※セキュリティグループにCloud9インスタンスからMariaDBへの接続を許可する設定を入れておいてください。
参考)そろそろaws初めてみよか#3~RDSとの接続~

ec2-user:~/environment/php-laravel (master) $ mysql -u admin -p -h laravel-db.culgyynq9ap1.us-east-2.rds.amazonaws.com
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 19
Server version: 5.5.5-10.2.21-MariaDB-log Source distribution

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> CREATE DATABASE laravel_dev DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;                                                                                                                                                               
Query OK, 1 row affected (0.01 sec)

mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| innodb             |
| laravel            |
| laravel_dev        |
| mysql              |
| performance_schema |
+--------------------+
6 rows in set (0.00 sec)

mysql> \q
Bye

php artisan migrateをしてみる

ec2-user:~/environment/php-laravel (master) $ php artisan migrate
Migration table created successfully.
Migrated: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_100000_create_password_resets_table

これで開発できますね^^

と思ったのですが…

php artisan serveができない...。
一難去ってまた一難。

一体どうやってaws上でlaravelプロジェクトを開発していくんでしょうか…。

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