Believe you can

If you can dream it, you can do it.

デスクを新調しました

新型コロナウィルスがまん延以降リモートワークを行っていますが、その前から子供のお古であるニトリの学習机をPCデスクとして活用していました。
これからもフルリートでお仕事をするので、妻にお願いして新しいPCデスクをようやく購入することができました。

今までのデスクはコチラ
f:id:chichi1091:20211123131522j:plain f:id:chichi1091:20211123131524j:plain

2つの学習机をL字にして使っていました。
自作PCと個人mac、仕事用macを利用しているためかなりゴチャゴチャしてますね。。

新しいデスクを設置する前に2つの学習机を処分する必要があります。長野市のゴミ処理場に自分で持っていけば、重さに応じてお支払いをすればいいんですが、さすがに学習机2つを自力で運ぶ車がありません。
写真には写っていませんが、机の横には2人掛けソファもあり一緒に廃棄もしたいので業者を探すところからはじめました。
(妻からはリビングにおいてある3人掛けソファも捨てたいと要望あり)

いくつかお問い合わせさせて頂いた結果、ご近所に不用品回収のマンモスさんにお願いさせていただきました。
予算にあう金額で、2階からの運び出しもしていただき大変助かりました!

manmosu.net

新しいデスクですが、荷物が多くあるので妻が許す予算の中でできる限り大きいデスクを探した結果、こちらになりました。

desk-ichiba.com

160cm幅のなかなかデカ目のデスクです。購入時はもうちょい安く購入することができました。
ということで新デスクがコチラ
f:id:chichi1091:20211123133137j:plain

とりあえず設置してみましたが、ごちゃり度はあまり変わらないですね。。(もっと真ん中で使えよって感じです)
使い始めて設置を改善していくしかないですね。

モニターをデスクトップとノートで共用している関係で設置が難しいのですが、皆さんどのようにされているんですかね?
ぜひアドバイスをいただけると幸いです!

LaravelでRESTfulAPIを作る〜その2〜

LaravelでAPIを作るの最終回です。MySQLとの接続を行っていきます。

Modelの作成

LaravelのORM、Eloquent(エロクアント)を使っていきます。
PHPが動いているDockerコンテナに入って artisan コマンドでModelを作ります。

$ docker-compose exec php bash
$ php artisan make:model Todos -f

App/Models 配下に Todos.php が作られます。

class Todos extends Model
{
    use HasFactory;
}
class TodosFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Todos::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            //
        ];
    }
}

調べていて気がついたのですが -c-r-api をつけることで Controllerも作ってくれるようです。
今回は -f オプションでモデルとファクトリを作成します。

Todosに追記

カラム情報とtimestampeがないことを定義します。

    protected $fillable = [
        'task',
    ];
    public $timestamps = false;

準備はこれで終わり。ControllerからModelを使ってDBアクセスをしてみます。

検索

Todos::all で全件を取得し、 Todos::find でプライマーキーで検索を行います。検索した結果をそのままレスポンスに返しています。
JSON_UNESCAPED_UNICODE はマルチバイト文字が文字化けを起こさないように設定しています。

    public function getTodos(Request $request): JsonResponse
    {
        $todos = Todos::all();
        return response()->json($todos, 200,
            ['Content-Type' => 'application/json;charset=UTF-8', 'Charset' => 'utf-8'],
            JSON_UNESCAPED_UNICODE);
    }

    public function getTodo(Request $request, int $id): JsonResponse
    {
        $todo = Todos::find($id);
        return response()->json($todo, 200,
            ['Content-Type' => 'application/json;charset=UTF-8', 'Charset' => 'utf-8'],
            JSON_UNESCAPED_UNICODE);
    }

登録、更新、削除

DB::beginTransactionトランザクションを開始し、成功時にはコミット、失敗時にはロールバックしています。
単一テーブルへの操作なので特に必要ないですが、お試しに入れてみました。Controllerにトランザクション処理があるのは正直気持ち悪さはありますがw

    public function createTodo(Request $request): JsonResponse
    {
        $task = $request->input('task');

        DB::beginTransaction();
        try {
            $new = Todos::create([
                'task' => $task,
            ]);
            DB::commit();
        } catch ($exception) {
            DB::rollBack();
        }

        return response()->json($new, 201,
            ['Content-Type' => 'application/json;charset=UTF-8', 'Charset' => 'utf-8'],
            JSON_UNESCAPED_UNICODE);
    }

    public function updateTodo(Request $request, int $id): JsonResponse
    {
        $task = $request->input('task');

        DB::beginTransaction();
        try {
            $todo = Todos::find($id);
            $todo->update(['task' => $task]);
            DB::commit();
        } catch ($exception) {
            DB::rollBack();
        }

        return response()->json($todo, 201,
            ['Content-Type' => 'application/json;charset=UTF-8', 'Charset' => 'utf-8'],
            JSON_UNESCAPED_UNICODE);
    }

    public function deleteTodo(Request $request, int $id): JsonResponse
    {
        DB::beginTransaction();
        try {
            $todo = Todos::find($id);
            $todo->delete();
            DB::commit();
        } catch ($exception) {
            DB::rollBack();
        }

        return response()->json(null, 200);
    }

まとめ

とりあえず目的のAPIを作ることはできました。検索はもっと複雑な絞り込みや結合を試さないとですし、ロジックをControllerに書いてしまっているのでソフトウェアアーキテクチャを導入して責務を明確にしてあげる必要がありますしユニットテストも書きたいし。まだまだやることはありますね。
それらについてはまだ後日余力があれば試したいと思います。
今回作ったソースはGitHubに上げてあります。

github.com

LaravelでRESTfulAPIを作る〜その1〜

前回の続きでLaravelでAPIを作っていきます。
以前の記事はこちら

chichi1091.hatenablog.jp

chichi1091.hatenablog.jp

作る内容はTODO用のAPIで元ネタは僕が技術書典9で頒布したKtorをLaravel版に作り変えていきます。詳細は以下を御覧ください。

github.com

techbookfest.org

DDLの準備

MySQLにテーブルを作成するためのDDLを用意します。 docker/db/sql配下に init.sql ファイルを作成します。

CREATE TABLE todos (
  id int(11) NOT NULL AUTO_INCREMENT,
  task TEXT NOT NULL,
  PRIMARY KEY (id)
);

ファイルを配置したらdocker-composeを起動させ、テーブルが作られていることを確認します。 もし作られないようであれば docker/db/data 内をすべて削除してから起動してみてください。

f:id:chichi1091:20211024162846p:plain

.env

LaravelからMySQLに接続するための設定を.envファイルに設定します。
その他にもRedisやメールサーバ、AWSの設定などがありますが、デフォルトのままでOKです。

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database
DB_USERNAME=docker
DB_PASSWORD=docker

初期画面の削除

RESTfulなAPIサーバになるので初期画面を表示は削除します。
server/routes/web.phpに書かれているルーティングはコメントにしておきます。 http://localhostにアクセスすると404が表示されます。

エンドポイント

APIの接続口となるエンドポイントを先に設定してしまいます。 今回利用するエンドポイントは以下になります。

  • GET /todos
  • GET /todos/{id}
  • POST /todos
  • PUT /todos/{id}
  • DELETE /todos/{id}

server/routes/api.php に追記します。

Route::get("/todos", [TodosController::class, "getTodos"]);
Route::get("/todos/{id}", [TodosController::class, "getTodo"]);
Route::post("/todos/{id}", [TodosController::class, "createTodo"]);
Route::put("/todos/{id}", [TodosController::class, "updateTodo"]);
Route::delete("/todos/{id}", [TodosController::class, "deleteTodo"]);

/todosにアクセスされると TodosControllergetTodos メソッドが呼び出されるという意味となります。

Controller

server/app/Http/ControllersTodosControllerクラスを作っていきます。とりあえず空っぽのResponseを返すようにしておき、実際のDBとの接続は次回としたいと思います。

<php

use Illuminate\Routing\Controller as BaseController;

class TodosController extends BaseController
{
    public function getTodos(Request $request): JsonResponse
    {
        return response()->json([], 200);
    }

    public function getTodo(Request $request, int $id): JsonResponse
    {
        return response()->json([], 200);
    }

    public function createTodo(Request $request, int $id): JsonResponse
    {
        return response()->json(null, 201);
    }

    public function updateTodo(Request $request, int $id): JsonResponse
    {
        return response()->json(null, 201);
    }

    public function deleteTodo(Request $request, int $id): JsonResponse
    {
        return response()->json(null, 201);
    }
}

curlAPIを叩いてみると空っぽのデータが返ります。

$ curl http://localhost/api/todos
[]

今回はここまで。次回はDBとの接続を行い完成を目指します。

Dockerに作ったPHP環境にIntellij IDEAで接続してDebugする

前回はDocker上にPHP環境を作るところまで行いました。今回はそのDocker上のPHPIntellij IDEAから接続してDebugするところまで作りたいと思います。

chichi1091.hatenablog.jp

この記事はIntellij IDEA Ultimate Editionで行っていますが、PhpStormでも同様の方法になると思います。(自信なし)
なお、私のIntellij IDEAは日本化されてますので適切に読み替えてください。

プラグインのインストール

※PhpStormをご利用の方は読み飛ばしていただいて大丈夫です。
Intellij IDEAにPHP関係のプラグインをインストールします。

  • PhpStorm Workshop
  • PHP
  • PHP Docker
  • Laravel

Dockerの設定

PreferencesDockerを開いて接続Dockerを設定します。
私の環境はmacですので Docker for Macを選択します。

f:id:chichi1091:20211011233650p:plain

次にPHPを選択して言語レベルとCLIを設定します。
言語レベルは利用しているPHPのバージョンに合わせて8.0を設定し、CLIインタプリタはDocker用をして新たに登録します。

Form Docker, Vagrant, VM, WSL, Remoteを選び画像のように設定します。
f:id:chichi1091:20211011234506p:plain

すると、DockerのPHPを読み込んでCLIインタプリタが作成されます。
f:id:chichi1091:20211011234647p:plain

最終的には次の画像のような設定となればOKです。
f:id:chichi1091:20211011234800p:plain

続いてPHP->サーバの設定を行います。これはDockerのXdebugに接続するために行います。ポイントはserver/var/wwwであることを紐付けることです。
f:id:chichi1091:20211012003501p:plain

実行

上部メニューの構成の追加をクリックしPHPリモートデバッグを登録します。
f:id:chichi1091:20211012000426p:plain

デバッグ実行の虫アイコンと電話のようなアイコンのリッスンを起動します。
適当な箇所にブレイクポイントを貼って http://localhostにアクセスすると指定した箇所で止まることができました。
f:id:chichi1091:20211012003234p:plain

かんたんに接続することができましたね。環境構築はこれで終わりで次回からはAPIサーバを作っていきたいと思います。

Docker上にLaravel環境構築

普段はJavaとSpringBootで開発しているのですが、PHPカンファレンス2021にスタッフ参加したことでモチベーションがあがりLaravelでなにか作りたいなと思い、環境構築しました。
数年前にPHP開発をしたこともありましたが、Vagrantを利用した環境だったので昨今の当たり前環境を学ぼうという魂胆もあります。

以下の環境を作ろうと思います。

図らずともバージョンは8で統一されましたw

ディレクトリ構成

以下の構成としました。多分よくある構成かと思われます。
serverにはLaravelのソースが入る形となります。

root
├ docker-compose.yml
├ docker
│  ├ php
│  │  ├ php.ini
│  │  └ Dockerfile
│  ├ db
│  │  ├ data
│  │  ├ logs
│  │  ├ sql
│  │  └ my.cnf
│  └ nginx
│    └ default.conf
└ server

docker-compose

詳しい解説はしませんが、PHP・Nginx・DBの3つのコンテナを立ち上げます。

version: '3'

services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
    - ./server:/var/www
    depends_on:
    - db

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

  db:
    image: mysql:8.0.26
    container_name: db
    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/logs:/var/log/mysql
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 3306:3306

PHP

PHPのコンテナにはcomposerを入れたりaptでモジュールを入れたりする必要があるのでDockerfileを用意します。
aptで入れているモジュールやdocker-php-ext-installはよくわからんので個別に調べないとだな。。。

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

RUN apt-get update \
  && apt-get upgrade -y \
  && apt-get install -y libicu-dev libzip-dev libonig-dev libssl-dev zip unzip \
  && docker-php-ext-install zip pdo_mysql \
  && pecl install xdebug \
  && docker-php-ext-enable xdebug

COPY --from=composer /usr/bin/composer /usr/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.iniです。これも特段説明することはないのですが、xdebugを入れています。今後はIntellij IDEA(PHPStorm)を使った開発を想定しているのでデバッグできるように入れています。

[Date]
date.timezone = "Asia/Tokyo"

[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

[xdebug]
xdebug.client_host = host.docker.internal
xdebug.client_port = 9003
xdebug.idekey = PHPSTORM
xdebug.mode = debug
xdebug.start_with_request = yes

Nginx

Nginxの設定ファイルです。今まではApachePHPを動かしていたので実はNginxは初めてです。。触ってみたいと思っていたのでNginxにしています。なのであまり説明できません、ごめんなさい。。。
ただ、ポイントとするとnginxコンテナのルートがserverになっているのでnginxのルートが /var/www/publicプロジェクトルート/server/publicということです。

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

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

  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;
  }
 }

MySQL

MySQLのデータを永続化するためにホストマシンに保持する形としています。sqlフォルダにDDLを配置しておけば起動時にテーブルを作ることも可能です。このあとTODOアプリを作ろうと思うのでDDLはこちらに配置することになります。
my.confもよくある設定だと思いますが、文字コード・ログ、スロークエリの出力についての設定です。

[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci

default-authentication-plugin = mysql_native_password

log-error = /var/log/mysql/mysql-error.log

slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 5.0
log_queries_not_using_indexes = 0

general_log = 1
general_log_file = /var/log/mysql/mysql-query.log

[client]
default-character-set=utf8mb4

プロジェクトの作成

Docker環境については以上でアプリケーションLaravelのプロジェクトを作っていきます。
コンテナを起動し、PHPコンテナでコマンドを実行します。

$ docker-compose up -d --build
$ docker-compose exec php bash
root@aafbcadd9d34:/var/www# composer create-project --prefer-dist laravel/laravel ./

しばらく待つと、serverディレクトが作られLaravelの各種ファイルが配置されます。

初期画面

ブラウザから http://localhost にアクセスするとLaravelの画面が表示されると思います。
昔の画面と違うんですね。もっとでかいLaravelって文字が真ん中にあった気がします。

f:id:chichi1091:20211009114718p:plain

まとめ

今回は初期画面が表示されるまでの環境構築になります。Dockerのおかげで非常にかんたんに構築することができますね。
次回以降はxdebugやRestAPIを作るところをやっていければと思います。

今回作った環境はGitHubにもアップしているので興味があれば参照してみてください。

github.com

PHPカンファレンス2021に当日スタッフとして参加しました(#phpcon2021)

2019、2020に続き今年もPHPカンファレンスの当日スタッフとして参加してきました。

phpcon.connpass.com

過去最高の応募人数となった今回のPHPカンファレンスですが、10/2、3の2日に渡って開催されました。

何してたの?

自分の役割はSNS担当とDiscordの盛り上げ係となります。
Twitter上で質問があれば回答したり、配信の遅れや連絡事項があればTwitterFacebookに投稿するといったことを行います。

前回も同じ役割だったし、SNS広報を取りまとめてくれている @mukakenさんが事前に説明してくれていたのでスムーズに行えたと思います。ありがとうございました!

Discordでは今回始めての試みとなるスポンサーツアーがあり基本そこに入り浸っていました。各企業のプロダクトやエンジニアリング文化など聞くことができスタッフでありながら楽しく参加することができました。今後もぜひ続けていただきたいですね。

次回も参加する?

オフライン開催でリモートスタッフが可能であればもちろん参加したいと考えています。とはいえ、配信現場のLIVEを見ているとやっぱ現地に行きたくなりますねw

次回は9/24、25に開催予定ですのでまだお会いできることを楽しみにしています。
コアスタッフ・運営委員、当日スタッフの皆様大変お疲れ様でした!

久しぶりに自作PC作った

自作PCが作りたい要求が出てきてしまったので、思い立って作ってみた。
(用途はこれから考えるのです。。)
前回PCを作ったのが学生時代なので約20年ぶり。壊さずつくれるかドキドキです。。。

せっかくPCを作るので、今使っているMacbook Airよりもスペックを上げつつ、予算は安ければ安いほどいいという条件にした。
以下の構成となった。購入は全てドスパラ

パーツ 金額
Core i5 10400F BOX(6C/12T) 15,980
PRIME B460M-A (B460 1200 MicroATX) 9,680
SSD 125GB 0 手持ちのSSDを流用
HDD 500GB 0 手持ちのHDDを流用
CMK32GX4M2A2666C16 (DDR4 PC4-21300 16GB 2枚組) 16,980
KRPW-L5-500W/80+ (500W) 4,480
CA-1J4-00S1WN-00 (Versa H18 MicroATX アクリル) 3,080
GTX1050 0 手持ちのグラボを流用

合計:50,200円

CPUをi3にしてメモリを減らせばもうちょい安く作れたけど、Macbook Airと似たスペックになってしまうので自分的には最安の構成。
とはいえグラボはサイズがあってないので早めに購入しないとです。。

基本的にはパーツを決まった箇所にはめるだけなのでそれほど悩まなかったですが、マザボとケースの配線、各種電源ケーブルの取り回しなどの配線が難しかった。
初心者向けにもうちょっとわかりやすい説明書を望みます。。。

せっかくそこそこのスペックを手に入れたので、ゲームや動画編集・プログラミングに活用しようと思います。
ただ、Windowsが久しぶりすぎて使いこなせないので慣れていかないと。