y-uchiida

Git for Windows でcore.useBuiltinFSMonitor=true is deprecatedのメッセージが表示される – core.fsmonitor=true を追加設定して解決

こんばんは、ウチイダです。

最近、VirtualBoxを使わなくてはいけない場面があります。

その時はWSLをオフにしているので、かわりにPowerShellやGit bashなどを使っています。

先日、git コマンドをPowerShellで利用したときに、以下のようなメッセージが表示されました。

hint: core.useBuiltinFSMonitor=true is deprecated;please set core.fsmonitor=true instead
hint: Disable this message with "git config advice.useCoreFSMonitorConfig false"

こんなの出ていたかな~と思いつつ検索してみると、2021年のリリースでgit for windowsに実験的に同梱されていたfs monitor を有効にするためのパラメータのようです。

現在は開発が進んで、実験的機能ではなく標準で提供されるものに位置付けられたので、パラメータの名称も変わって、古い方が非推奨になった…ということのようでした。

特に支障はないらしいのですが、毎回出てきてうっとうしいので、表示されないようにしたいと思います。

とりあえずメッセージに従って、fsmonitor の設定値をtrueにします。

> git config --global core.fsmonitor true

これでメッセージは表示されなくなりました。

ちなみに、fsmonitor というのは、gitコマンドの動作を高速化するために内部的に使われているプログラムだとのこと。

詳しく調べられませんでしたが、有効にしておいて問題はなさそうなので、いったんこのまま様子を見ようと思います。

以上です。あなたのお役に立てれば幸いです。

composer self-update がnot defined になってしまう – 最新版を別インストールする

こんばんは、ウチイダです。

ご依頼いただいている案件で、XserverにLaravelアプリケーションをデプロイするときにちょっとつまづいたのでメモしておきます。

Xserverにはもともとcomposer がインストールされているのですが、バージョンが古くてうまくいかないことが発生します。

サーバを立てたタイミングによるかもしれませんが、2022年5月時点で、以下のバージョンが動きます。

$ composer -V
Composer version 1.9.1 2019-11-01 17:20:17

v1系ですね…

最新はv2.3 なので、これだといろいろエラーが出てしまいます。

というわけでアップデートをかけたいのですが、self-updateができないように設定されていました。

$ composer self-update

  [Symfony\Component\Console\Exception\CommandNotFoundException]
  Command "self-update" is not defined.

レンタルサーバだし仕方ない。

というわけで、最新版をインストールします。

多くのサイトでComposerのインストールコマンドが紹介されているのですが、バージョンが古いものだと、ハッシュチェックでエラーになってしまうので、必ず公式サイトのコマンドを参照するようにしましょう…

https://getcomposer.org/download/

このページにインストールコマンドを掲載すると、時間がたったときにここを見ていただいた方をエラーに導いてしまうことになるので、あえて書かないことにします。

上記の公式サイトに掲載されている最新のコマンドでcomposer-setup.php を取得して、ハッシュも最新のファイルのものを利用してください。

あとはインストールするだけです。

/usr/bin には先住Composerがいるので、ここには配置できまん。

パスが通っている別のディレクトリに置くか、新たにパスを通したディレクトリに配置します。

今回はホームディレクトリ配下に.composer を作って、そこに住まわせることにしました。

同じルールでnodebrewとかもインストールされていたので、それに合わせる形です。

composer-setup.php には、インストール先を指定するオプションがついているので、これを利用しました。

$ php composer-setup.php --install-dir=~/.composer --filename=composer;

パスは通してくれなかったので、手動で追加しました。

$ echo "export PATH=$HOME/.composer:$PATH" >> ~/.bashrc

バージョンチェックをして、最新版になっていれば完了です!

$ composer -V
Composer version 2.3.5 2022-04-13 16:43:00

Xserverはレンタルサーバーのくせにいろいろカスタマイズできて便利ですが、ひと工夫必要な場面もあるので、落ち着いてデプロイ作業を行いたいですね。

以上です。あなたのお役に立てれば幸いです。

Laravel artisan でClassloader のエラーが発生 – composer dumpautoload でオートロード設定を更新

こんばんは、ウチイダです。

Laravel にいろいろなパッケージを追加していたところ、あるタイミングからartisan コマンドの実行で以下のようなエラーが発生するようになりました。

例ではEvent クラスの生成コマンドを試していますが、ほかのコマンドでも同様です。

$ php artisan event:generate

   ErrorException

  include(/var/www/html/vendor/composer/../../app/Events/Something.php): Failed to open stream: No such file or directory

  at vendor/composer/ClassLoader.php:571
    567▕  * @private
    568▕  */
    569▕ function includeFile($file)
    570▕ {
  ➜ 571▕     include $file;
    572▕ }
    573▕

      +2 vendor frames
  3   [internal]:0
      Composer\Autoload\ClassLoader::loadClass()

      +27 vendor frames
  31  artisan:37
      Illuminate\Foundation\Console\Kernel::handle()

どうやら、Composerのオートロードがうまく動作していないようです。

Composerでのパッケージ追加中に、何かの操作をミスったか、composer.jsonの設定を間違えたようです。

以下のコマンドで修正をかけます。

$ composer dumpautoload
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: barryvdh/laravel-debugbar
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: spatie/laravel-ignition

# ... 他にもいろいろ表示されました ...

Package manifest generated successfully.
Generated optimized autoload files containing 5207 classes

再度、Event クラスの生成を試したところ、うまくいきました。

$ artisan event:generate
Events and listeners generated successfully.

以上です。あなたのお役に立てれば幸いです。

Laravel Http クライアントで、Gzipのデータを取得したい

こんばんは、ウチイダです。

Amazon Ads API を利用して、広告費用を最適化するアプリケーションの開発をご依頼いただきました。

ドキュメントが今のところ英語しかないので、頑張って読み解きつつ進めています。

https://advertising.amazon.com/API/docs

LaravelでAmazon Ads APIとの通信部分を実装しているなかで、広告パフォーマンスのレポートデータをダウンロードする部分で少し苦労したのでメモしておきます。

Amazon Ads API では、クリック数や広告経由の売り上げなどの情報を取得するために、以下の手順を踏む必要があります。

  1. レポートデータの生成をリクエスト
  2. 最大15分ほど、レポートデータが生成されるのを待つ
  3. レポートデータが生成されたら、Amazon S3からダウンロードする

3でダウンロードされるデータがgzipで圧縮されていたので、うまくレスポンスを受け取るのに少し工夫が必要でした。

ちなみに、手順1, 2はLaravel Httpのドキュメントを見ながら結構簡単に実装できました。

https://readouble.com/laravel/9.x/ja/http-client.html

実際にうまく動作したコードは、以下のような感じです。

// 冒頭で、Http ファサードを読み込んでおく
use Illuminate\Support\Facades\Http;

$response = Http::
    withHeaders([
    'Content-Type' => 'application/json',
    'Amazon-Advertising-API-ClientId' => 'CLIENT_ID', // あらかじめ取得したClient IDを設定
    'Amazon-Advertising-API-Scope' => 'PLOFILE_ID', // あらかじめ取得したProfile IDを設定
])
    ->withOptions(['decode_content' => 'gzip']) // ★gzip形式での受け取りする
    ->withToken('ACCESS_TOKEN') // あらかじめ取得したアクセストークンを設定 WithToken() がBearer の記述など行ってくれる
    ->get("https://advertising-api-fe.amazon.com/v2/reports/{$reportId}/download"); // あらかじめ発行リクエストしたレポートのIDを設定

dump($response->body()); // gzip のバイトデータそのまま表示してみる
dump(gzdecode($response->body())); でコードしてもともとのデータを表示する

downloadのエンドポイントは、存在するレポートデータのIDに対してリクエストされたら、リダイレクトしてAmazonS3 バケットに配置されたデータを返してくれます。

Content-typeはapplication/jsonにしつつ、gzipのデータを取得するように設定する必要があります。

ポイントはwithOptions()でgzipのデータを受け取ることを記述している点です。

‘decode_content’ で指定できるのですね。

この設定値はLaravelのドキュメントには記載されていなくて、Guzzle のドキュメントを見る必要がありました。

https://docs.guzzlephp.org/en/stable/request-options.html#decode-content

ちなみに、ヘッダー内に書く場合は以下のようになります。

// 冒頭で、Http ファサードを読み込んでおく
use Illuminate\Support\Facades\Http;

$response = Http::
    withHeaders([
    'Content-Type' => 'application/json',
    'Amazon-Advertising-API-ClientId' => 'CLIENT_ID', // あらかじめ取得したClient IDを設定
    'Amazon-Advertising-API-Scope' => 'PLOFILE_ID', // あらかじめ取得したProfile IDを設定
    'Accept-Encoding' => 'gzip' // ★ここにgzipを指定
])
    ->withToken('ACCESS_TOKEN') // あらかじめ取得したアクセストークンを設定 WithToken() がBearer の記述など行ってくれる
    ->get("https://advertising-api-fe.amazon.com/v2/reports/{$reportId}/download"); // あらかじめ発行リクエストしたレポートのIDを設定

withOptions() がなくなってチェインするメソッドが減ったので、今回の場合であればこっちの方がすっきりします。

withToken()も、Bearer の記述をコード内に書けばwithHeaders() に含めることができるので、もっとまとめてしまうこともできます。

ウチイダ的にはwithToken() を使う方が楽なので、このままにしています。

以上です。あなたのお役に立てれば幸いです。

Git で、ファイルの一部の変更のみコミットしたい – git add -p

こんばんは、ウチイダです。

ここしばらく、10名くらいのグループで開発する案件で、デプロイ内容の確認などを行う役割を任せていただいてます。

それ以来、gitのいろんな機能を活用する機会が増えました。

その中でも、しばしば利用するのに毎回忘れてしまうのが「ファイルの一部分の変更だけコミットする」というもの。

コマンドラインから簡単にできます。

# 指定ファイルの変更内容ごとに、add するか確認する
$ git add -p filename

git add -p でファイル名を指定すると、変更箇所(hunk) ごとにコミットステージに乗せるかを確認してくれます。

今回のコミットに含めたい部分はy, それ以外はn を入力していきます。

あとはいつもどおりにコミットすればOKです。

実装内容の切り戻しや、プロダクション環境へのリリースに際して、コミットは細かくしてあったほうが便利だなと最近実感しています。

RevertやCherryPickの操作をするときに、細分化してある方が結果的に楽なんですよね…

以上です。

あなたのお役に立てれば幸いです。

Laravelで複数のDBへ接続する

こんばんは、ウチイダです。

この前お引き受けしたお仕事で、複数のDBサーバを利用する案件がありました。

  • 全データを集積しているDB(マスタDB)から必要な内容を取得し、自前のDB(アプリDB)に保存
  • アプリDBには、独自に算出して業務に用いるカラムがある

という感じに開発するもので、モデル自体を別のものとして扱う方がよさそうでした。

というわけで、モデルごとに、別のDBのテーブルと連携させるための設定を調べました。

それをメモしておきます。

ちなみに、利用したLaravelのバージョンは9です。

今後の新規プロジェクトで利用できると思います。

1. .envに接続情報を分けて記載する

.envに、二つのDBの接続情報を記載します。以下のような感じです。

※もちろん、値はすべて仮のものです。

# 自前のDB(アプリDB)接続設定
APP_DB_CONNECTION=app
APP_DB_HOST=app.example.com
APP_DB_PORT=3306
APP_DB_DATABASE=app
APP_DB_USERNAME=app_user
APP_DB_PASSWORD=password

# データを集積しているDB(マスタDB)の接続設定
MASTER_DB_CONNECTION=master
MASTER_DB_HOST=master.example.com
MASTER_DB_PORT=3306
MASTER_DATABASE=master
MASTER_DB_USERNAME=master_user
MASTER_DB_PASSWORD=password

2. LaravelのDB接続設定で、envに記載した内容を反映

config/database.php で、データベースの接続設定がまとめられています。

.envで指定した内容がLaravel内で利用できるように設定していきます。

設定項目が多いように見えますが、デフォルトで「mysql」 という名前の接続情報があるので、それをベースに一部を書き換えるだけなので、それほど難しくはありません。

    /* 18行目あたり */
    /* デフォルトの接続情報はappにする */
    'default' => env('APP_DB_CONNECTION', 'app'),

    /* connections の中で、.envに指定した内容を記入する */
    'connections' = [
        /* アプリDB用の接続設定 */
        'app' => [
            'driver' => 'mysql',
            'url' => env('APP_DB_URL'),
            'host' => env('APP_DB_HOST', '127.0.0.1'),
            'port' => env('APP_DB_PORT', '3306'),
            'database' => env('APP_DATABASE', ''),
            'username' => env('APP_DB_USERNAME', ''),
            'password' => env('APP_DB_PASSWORD', ''),
            'unix_socket' => env('APP_DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

        /* マスタDB用の接続設定 */
        'app' => [
            'driver' => 'mysql',
            'url' => env('MASTER_DB_URL'),
            'host' => env('MASTER_DB_HOST', '127.0.0.1'),
            'port' => env('MASTER_DB_PORT', '3306'),
            'database' => env('MASTER_DATABASE', ''),
            'username' => env('MASTER_DB_USERNAME', ''),
            'password' => env('MASTER_DB_PASSWORD', ''),
            'unix_socket' => env('MASTER_DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],
    ],

3. モデルファイルで、接続先のDBを指定する

次に、モデルファイルに$connection を追加し、利用する接続先の名称を指定します。

以下は、アプリDBのsamples テーブルを利用するモデルの例です。

<?php

namespace App\Models\App;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Sample extends Model
{
    use HasFactory;

    /* アプリDBへ接続する */
    protected $connection = 'app';
}

4. モデルを使ってみる

これで準備は整いました。ためしに、コントローラから呼び出してみます。

<?php

namespace App\Http\Controllers;

use App\Models\App\Sample;

class ConnectionTestController extends Controller
{

    public function test()
    {
        /* samples テーブルから1件データを取り出してみる */
        dd(Sample::first());
    }
}

ルーティング設定してブラウザからアクセスし、データが表示されたら成功です。

同じ要領で、マスタDB用のモデルも作成できます。

cinfig/connection.php に接続情報をまとめていることが理解できていれば、記述するコードの内容は想定してたより難しくありません。

フレームワークごとに設定の仕方はいろいろなので、このあたりは実際に案件を通じて経験したり、じっくりドキュメントなどを読んで理解を深めていくことが不可欠ですね。

おまけ:DB ファサードで接続先を指定する

上記の設定をした前提で、DB ファサードからマスタDBへ接続する場合は以下のようにします。

DB::connection('master')->table('sample')->first();

connection() メソッドを書かなければ、デフォルト設定しているapp が使われます。

以上です。あなたのお役に立てれば幸いです。

Docker コンテナのリソース使用率を調べるのに便利なコマンド ctop

こんばんは、ウチイダです。

先日、Webアプリケーションのチューニングコンテストに参加しました。

パフォーマンスの計測とボトルネックの発見を担当したのですが、その際に使用したctop というコマンドが便利だったのでメモしておきます。

公式リポジトリはこちらです。

https://github.com/bcicen/ctop

WSL2 へのインストールは以下でできました。

$ sudo wget https://github.com/bcicen/ctop/releases/download/v0.7.1/ctop-0.7.1-linux-amd64  -O /usr/local/bin/ctop
$ sudo chmod +x /usr/local/bin/ctop

Docker コンテナの稼働状況をみたいのがウチイダの用途なので、–type オプションをつけて実行します。

$ ctop --type=docker

Laravel Sailのコンテナを立ち上げて、上記コマンドを実行すると、以下のようにモニタリングできます。

dtop –type=docker 実行結果

スクリーンショットだと見切れていますが、CGROUP のところにグループ名が書かれていて、どのコンテナかわかるようになっています。

上下キーでコンテナを選択して、 e キーでコンテナのターミナルをすぐ開けるのも便利です。

以上、あなたのお役に立てれば幸いです。

Laravel 9 にLaravel Mix でjQuery を追加する

こんばんは、ウチイダです。

Laravelの案件でも、フロントをjQueryにするパターンはちょいちょいありますね。

初期構築の際、いつもインストールに手間取るので、未来の自分のために書いておくことにします。

vueのやり方は検索に出てくるんですけど、jQuery はないのはなぜなのでしょうね…?

1. npm でjQuery をインストール

$ npm install jquery --save-dev 

2. webpack.mix.js を編集

autoload() でjQueryを指定するだけで、public/app.jsにも含まれるし、$で呼び出せるようにもなります。

bootstrap.js などrequire() を書く必要があるのかと思ってしまうのですが、それもいりません。

mix.js("resources/js/app.js", "public/js")
    .sass("resources/scss/custom.scss", "public/css")
    .postCss("resources/css/app.css", "public/css", [
    ])
    /* 以下を追記 */
    .autoload({
        jquery: ["$", "window.jQuery"],
    });
    /* 追記ここまで */

3. npm run でコンパイル

コンパイルします。

$ npm run dev

全く関係ないですが、コンパイルは機械語への変換のことだと理解していたので、JavaScript を「コンパイルする」という言葉遣いはいまだに違和感がぬぐえないんですよね…

4. View で読み込み

Blade テンプレートのヘッダ部分などに、以下を追記します。

<script src="{{ mix('js/app.js') }}"></script>

以上です。

あなたのお役に立てれば幸いです。

Laravel sail で外部APIアクセスエラーする

こんばんは、ウチイダです。

先日お引き受けした案件で、Laravelから外部APIを利用する実装が必要になりました。

いつものように、ローカル環境のSailで動作確認しつつ実装していきます。

しかし、Httpファサードで外部APIにアクセスしようとするとResolving タイムアウトが発生してしまいました。

どうやら、名前解決に失敗しているみたいです。

Dockerネットワーク外のドメインの名前解決をするDNSが設定されていないことが原因だったので、Docker-compose.ymlに、dnsを設定しました。

# For more information: https://laravel.com/docs/sail
version: '3'
services:
    laravel.test:
				# (略)

        # 外部DNSを指定する
        dns: 8.8.8.8

いったんコンテナを再起動してDNSを認識できるようにしてからリトライ。

APIサーバを見つけて、レスポンスを取ることができました。

ちなみに、これに苦労してあれこれコントローラのアクションメソッドに書き散らかしてしまったので、その後サービスクラスに切り出すのにそこそこ苦労しました(現在進行形でしてます)。

思いがけない沼にはまると、設計やクラス分解がおろそかになりがちなので気を付けたいです。

以上です。

あなたのお役に立てれば幸いです。

Laravel Sailに追加したPhpMyAdminからデータベースにつながらない

先日、Laravel Sailについて質問を受けた内容です。

PhpMyAdminを使いたいということで、自身で調べてdocker-composeにサービスの追加をしたけど、動かないということでした。

Sail を起動して、ブラウザでPhpMyAdminにログインしようとすると、エラーになってしまいます。

ログインの時点でエラー

とりあえずMySQLの疎通確認から。

Laravelコンテナからマイグレーションの実行はできているので、MySQLコンテナ自体はちゃんと動いているようです。

$ sail artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (553.47ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (767.61ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (589.25ms)
Migrating: 2019_12_14_000001_create_personal_access_tokens_table
Migrated:  2019_12_14_000001_create_personal_access_tokens_table (380.02ms)

コンテナ起動時にも、ちゃんとphpmyadminコンテナが起動してます。

$ sail up -d
Creating network "laraveltest_phpmyadmin_sail" with driver "bridge"
Creating laraveltest_phpmyadmin_mailhog_1     ... done
Creating laraveltest_phpmyadmin_redis_1       ... done
Creating laraveltest_phpmyadmin_mysql_1       ... done
Creating laraveltest_phpmyadmin_selenium_1    ... done
Creating laraveltest_phpmyadmin_meilisearch_1 ... done
Creating laraveltest_phpmyadmin_phpmyadmin_1   ... done
Creating laraveltest_phpmyadmin_laravel.test_1 ... done

$ sail ps
                Name                               Command                  State                           Ports
--------------------------------------------------------------------------------------------------------------------------------------
laraveltest_phpmyadmin_laravel.test_1   start-container                  Up             0.0.0.0:80->80/tcp, 8000/tcp
laraveltest_phpmyadmin_mailhog_1        MailHog                          Up             0.0.0.0:1025->1025/tcp, 0.0.0.0:8025->8025/tcp
laraveltest_phpmyadmin_meilisearch_1    tini -- /bin/sh -c ./meili ...   Up (healthy)   0.0.0.0:7700->7700/tcp
laraveltest_phpmyadmin_mysql_1          /entrypoint.sh mysqld            Up (healthy)   0.0.0.0:3306->3306/tcp, 33060/tcp, 33061/tcp
laraveltest_phpmyadmin_phpmyadmin_1     /docker-entrypoint.sh apac ...   Up             0.0.0.0:8080->80/tcp
laraveltest_phpmyadmin_redis_1          docker-entrypoint.sh redis ...   Up (healthy)   0.0.0.0:6379->6379/tcp
laraveltest_phpmyadmin_selenium_1       /opt/bin/entry_point.sh          Up             4444/tcp, 5900/tcp

Laravel本体のコンテナとMySQLのコンテナは疎通してて、PhpMyAdminからだとつながってないような状況なので、コンテナ内でなんか起こってるのかなと目星をつけました。

ご質問者さんに了解を取ったうえで、ボリュームを削除して作り直してみます。

sail down --volumes --remove-orphans
Stopping laraveltest_phpmyadmin_laravel.test_1 ... done
Stopping laraveltest_phpmyadmin_phpmyadmin_1   ... done
Stopping laraveltest_phpmyadmin_meilisearch_1  ... done
Stopping laraveltest_phpmyadmin_selenium_1     ... done
Stopping laraveltest_phpmyadmin_mysql_1        ... done
Stopping laraveltest_phpmyadmin_redis_1        ... done
Stopping laraveltest_phpmyadmin_mailhog_1      ... done
Removing laraveltest_phpmyadmin_laravel.test_1 ... done
Removing laraveltest_phpmyadmin_phpmyadmin_1   ... done
Removing laraveltest_phpmyadmin_meilisearch_1  ... done
Removing laraveltest_phpmyadmin_selenium_1     ... done
Removing laraveltest_phpmyadmin_mysql_1        ... done
Removing laraveltest_phpmyadmin_redis_1        ... done
Removing laraveltest_phpmyadmin_mailhog_1      ... done
Removing network laraveltest_phpmyadmin_sail
Removing volume laraveltest_phpmyadmin_sail-mysql
Removing volume laraveltest_phpmyadmin_sail-redis
Removing volume laraveltest_phpmyadmin_sail-meilisearch

これで直りました。どういう事象でエラーだったのかわからないけど。。。

ボリュームを消しちゃったので、MySQLも空っぽになっています。

このあと、マイグレーション・シーディングをし直してもらいました。

以上です。あなたのお役に立てれば幸いです。