PHPerKaigi2021に参加しました!

メモな感じですが投稿します!(iwillblogって書いちゃったので…)
はじめてのニコニコ動画使用でした(会員登録はいつのまにかしてた)

景品が豪華すぎて当たった方うらやましいです😭

\スタッフ、スピーカーのみなさま、ありがとうございました🙇‍♂️/

勉強させてもらったセッション一覧

他にも見たかったものやもう一回見たいセッションがいっぱいあるので、アーカイブ待ってます!

 

各セッションのメモ

テスト放送

[初心者向け] 一からフレームワークを作るところを見せる

  • リアルタイムでコードを書いているところが見れて良かった。
  • ディレクトリトラバーサル攻撃に気をつけよう。
  • フレームワーク作りたくなった、作ろう。(iwillframework)

Symfonyラウンドテーブル(よろず相談会)

  • symfony/pantherすごそう。GithubActionで動いたことが謎らしいが、なんで謎なのかさえも私はわかっていない。。。

PHPで学ぶ、セッションの基本と応用

  • Cookieの仕様(RCF6265)ちゃんと読もう

PHP8になった今の時代に、PHPの「エラー」「例外」そして「Error」をおさらいしておこう

  • 例外は独自に定義しよう。(無駄なサードパーティの露呈を防ぐためにも)

@call_user_func(関数ではない)の使いこなしテクと(ルーレッ…

  • このbotを使った遊び方を理解した
  • twitterの検索例「from:call_user_func url:gitee」
  • リポジトリのnamespace抑える為だけにリポジトリ作る人もいるらしい、ドメインみたいな感じ(?)私もしようかな。

そのコード、フレームワークの外でも動きますか?

  • LaravelSymfonyへの移行を見れたのが良かった
  • やっぱり例外は独自に定義しよう。(2回目)
  • LaravelのModelはSymfonyのEntity
  • Symfonyのお作法で404エラーはBadRequestHttpException
  • Vanilla PHPを書こう!
  • Symfony、Laravel、CakePHPどんなPHPフレームワークからも使えるPHPが最高🍺

なるせ先生のPHP学~PHP8新機能スペシャル~ (ちょっとだけ)

  • 移動中スマホからちょっと見れたが動画クオリティが凄かった。
  • しばらくコード書いておらず、初耳学ばかりで勉強になった。
  • ちゃんと全部見たい!!!

今こそ理解するDI(Dependency Injection)

  • そういえばDIってデザインパターンだったことを再認識した。
  • DIは保守性の高いコードを書く事を目的とした方法論
  • DIとDIコンテナは別物、 DIコンテナはDIパターンをサポートするライブラリ
  • DIとerviceLocatorの違いは私自身イマイチ理解できてない。

DNSを制するものはインターネットを制す! DNSの世界

  • DNS苦手意識があるけど、ドメインハイジャックでCoinCheckの事件とか色々あるので逃げずにNSchecker使ってみたいと思いました。
  • 子供Youtubeを8時以降禁止にするための方法はわたしも親になったのでいつか使えそうと感じた。

 

おまけ

ノベルティめっちゃ良かったです、ホットアイマスク最高でした😏

エコバック今日の買い出しにも使いました。

カレーは緊急用にとっておっきます〜

「fn」というワードはPHP7.4から予約語に!(→アロー関数)

 

「fn」というワードはPHP7.4から予約語になったというのを知るに至った経緯として、$ symfony serveでローカルサーバを立てて

$ symfony serve
                                                                                                                        
 [OK] Web server listening                                                                                              
      The Web server is using PHP FPM 7.3.11                                                                            
      https://127.0.0.1:8000                                         


[Web Server ] Jan 18 18:48:55 |INFO   | PHP    listening path="/usr/sbin/php-fpm" php="7.3.11" port=61746                                              

 

ブラウザで表示確認をすると、以下の500エラーがでました😱

(phpenvでいろんなPHPバージョンを使ってます。)

HTTP 500 Internal Server Error
syntax error, unexpected 'fn' (T_STRING), expecting :: (T_PAAMAYIM_NEKUDOTAYIM)
ParseError
in /Users/xxx/my-project/vendor/laminas/laminas-code/src/Generator/ClassGenerator.php (line 480)
470    /**
471     * @param string $implementedInterface
472     * @return bool
473     */
474    public function hasImplementedInterface($implementedInterface)
475    {
476        $interfaceType = TypeGenerator::fromTypeString($implementedInterface);
477
478        return (bool) array_filter(
479            array_map([TypeGenerator::class, 'fromTypeString'], $this->implementedInterfaces),
480            static fn (TypeGenerator $interface): bool => $interfaceType->equals($interface)
481        );
482    }

 

よーく確認してみると、
symfony php --versionphp --versionのバージョンが違う」
ことに気づきました💦

$ symfony php --version
PHP 7.3.11 (cli) (built: Jun  5 2020 23:50:40) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.11, Copyright (c) 1998-2018 Zend Technologies

$ php --version
PHP 7.4.9 (cli) (built: Dec 26 2020 23:21:06) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.9, Copyright (c), by Zend Technologies
    with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans

 

そこで、$ symfony serve でもPHP 7.4.9で動くように設定します。

参照:https://symfony.com/doc/current/setup/symfony_server.html#different-php-settings-per-project

$ cd my-project/

$ echo 7.4.9 > .php-version

$ symfony php --version # PHP 7.3.11 -> 7.4.9に変更完了
PHP 7.4.9 (cli) (built: Dec 26 2020 23:21:06) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.9, Copyright (c), by Zend Technologies
    with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans


$ symfony serve # PHP 7.4.9でサーバ立てることに成功

                                                                                                                        
 [OK] Web server listening                                                                                              
      The Web server is using PHP FPM 7.4.9                                                                             
      https://127.0.0.1:8000                                                                                     

[Web Server ] Jan 18 18:50:59 |INFO   | PHP    listening path="/Users/xxx/.phpenv/versions/7.4.9/sbin/php-fpm" php="7.4.9" port=62271

お! PHP7.4.9でサーバ立てるようになったみたいです!
と同時にsyntax error, unexpected 'fn' (T_STRING), expecting :: (T_PAAMAYIM_NEKUDOTAYIM)のエラーもなくなりました🎉

めでたし、めでたし👏

 

syntax error, unexpected ‘fn’ (T_STRING), expecting :: (T_PAAMAYIM_NEKUDOTAYIM)の解明

参照:https://www.php.net/manual/ja/tokens.php

 

Google翻訳先生に訳してもらうと、

構文エラー、予期しない '楽しい'(t_string)、予期する::( t_pamaim_nikoodatim)

おそらく fn = 楽しい って訳してくれてます💦

ググっていくと、「fn」はPHP7.4から予約語になったらしいです!

というかアロー関数(無名関数)が使えるようになり、その予約語としてfnを使います。

(風の噂でアロー関数が使えるようになったというのは知っていたのですが書き方まで知らなかったです😅)

アロー関数は fn (argument_list) => expr という形で記述します。

よって、PHP 7.4まではアロー関数がなかったために以下の該当箇所を、「::」を使うスコープ定義演算子 (::)のことではないですか?と教えてくれたのかもしれません。

static fn (TypeGenerator $interface): bool => $interfaceType->equals($interface)

 

CIのComposerバージョンが2になる(composer self-updateさせてた)せいでテストがコケてた話

今回の目標

CIをphp7.4に対応したい
(Herokuでは既に7.4.7だったので)

 

.circleci/config.ymlのimageをcircleci/php:7.4-node-browsers
にしたところ、composer-plugin-apiに関するエラーが発生しました。

Composer2でcomposer installを実行したのに、composer.lockでcomposer-plugin-apiは1系って書いてあるから互換性ないやないかーみたいなこと言ってる、おそらく。Composer2はcomposer-plugin-api2系使えってこと?

($ composer install -n –prefer-dist以下)

$ php --version
PHP 7.4.9 (cli) (built: Dec 26 2020 23:21:06) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Zend OPcache v7.4.9, Copyright (c), by Zend Technologies
with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans

$ composer --version
Composer version 2.0.8 2020-12-03 17:20:38

$ composer install -n --prefer-dist
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Your lock file does not contain a compatible set of packages. Please run composer update.

Problem 1
- ocramius/package-versions is locked to version 1.4.2 and an update of this package was not requested.
- ocramius/package-versions 1.4.2 requires composer-plugin-api ^1.0.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
Problem 2
- symfony/flex is locked to version v1.5.3 and an update of this package was not requested.
- symfony/flex v1.5.3 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
Problem 3
- ocramius/package-versions 1.4.2 requires composer-plugin-api ^1.0.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
- ocramius/proxy-manager 2.1.1 requires ocramius/package-versions ^1.1.1 -> satisfiable by ocramius/package-versions[1.4.2].
- ocramius/proxy-manager is locked to version 2.1.1 and an update of this package was not requested.

ocramius/package-versions only provides support for Composer 2 in 1.8+, which requires PHP 7.4.
If you can not upgrade PHP you can require composer/package-versions-deprecated to resolve this with PHP 7.0+.

You are using Composer 2, which some of your plugins seem to be incompatible with. Make sure you update your plugins or report a plugin-issue to ask them to support Composer 2.

 

そもそもCircleCIを導入しようとしてましたが、すでにTravis導入済みだったのでCircleCI導入はやめました。すみません💦(ただエラー内容はだいたい一緒だったと思います。)

当時設定していた.travis.ymlのPHPバージョンが7.1~7.3だったので7.4にしようと思います。

ローカルではcomposer1.8系を使っていたのでエラーはみられませんでしたが、
.travis.yamlではbefore_install: composer self-updateにしてたのでcomposer2系でcomposer installを実行しようとしていました。

エラー内容:

xxx/yyy n.n.n requires composer-plugin-api ^1.0.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.

composer.jsonのrequireにcomposer-plugin-api: "^1.0 || ^2.0"を追記で↑のエラーは回避できました!!!

参考:https://github.com/composer/composer/issues/8726

 

[おまけ]composer validate追記したらエラーでた

実際にでてたエラーログです。

$ composer validate
./composer.json is valid for simple usage with composer but has
strict errors that make it unable to be published as a package:
See https://getcomposer.org/doc/04-schema.md for details on the schema
name : The property name is required
description : The property description is required
symfony/debug-pack, symfony/maker-bundle, symfony/profiler-pack, symfony/test-pack are required both in require and require-dev, this can lead to unexpected behavior
require.symfony/debug-pack : unbound version constraints (*) should be avoided
require.symfony/orm-pack : unbound version constraints (*) should be avoided
require.symfony/profiler-pack : unbound version constraints (*) should be avoided
require.symfony/serializer-pack : unbound version constraints (*) should be avoided
require.symfony/test-pack : unbound version constraints (*) should be avoided
require.symfony/twig-pack : unbound version constraints (*) should be avoided

 

1) エラー内容:
xxx/yyy are required both in require and require-dev, this can lead to unexpected behavior

→ requireとrequire-devに同じpackageが書いてあるのがダメみたいなのでrequire-devから重複削除しました。

 

2) エラー内容:
name : The property name is required
description : The property description is required

→ composer.jsonにnameとdescriptionが必要とのことなので、追加しました。

 

3) エラー内容:
require.xxx/yyy: unbound version constraints (*) should be avoided

→ xxx/yyy: "*"はやめるべきとのことなのでバージョン指定をしました。

 

すべて(今回は3つ)のエラーを解消させ、

composer updateでcomposer.lockを更新して再度composer validateするvalidになりました〜🙌

$ composer validate
./composer.json is valid

 

メモ

  • 今回対応での差分

https://github.com/kin29/dj-kin29/pull/10/files

 

 

  • 後々考えてみたら、ローカル環境のcomposerバージョンを2にして、composer updateでcomposer.lockを更新してcommitで良かったのかも😅

composer-plugin-api:^2.0に対応してないpackageだったら、composer.jsonのrequireにcomposer-plugin-api: "^1.0 || ^2.0"追記が必要なのかも。

 

 

phpenvでPHP7.4系を導入した(configure optionをちょっと深ぼる)

 

実行環境は、macOS Catalina 10.15.7 です。

macOS Big Sur にアップデートしたらどうなるんだろうか….🤔迷ってます

 

(過去記事でphpenvでよく使うコマンドまとめてます。)

phpenvでいろんなPHPバージョンを操る

 

しばらくコードを書いておらず、PHPのバージョンが7.3.7だったので7.4系にバージョンあげますー😅

$ php --version
PHP 7.3.7 (cli) (built: Oct  6 2020 15:27:59) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.7, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.7, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v2.7.2, Copyright (c) 2002-2019, by Derick Rethans

$ phpenv versionsに7.4系が入ってなかったので、

$ phpenv update

からの

$ phpenv install 7.4.9

を実行したら、

-----------------------------------------
configure: error: Please reinstall the BZip2 distribution
-----------------------------------------

といわれたので、
bzip2をreinstallしてパスも通しましたが解決しませんでした。

ググって以下でinstallしてみました。

$ PHP_RPATHS="/usr/local/opt/bzip2/lib" PHP_BUILD_CONFIGURE_OPTS="--with-bz2=/usr/local/opt/bzip2" phpenv install 7.4.9

そしたら、

-----------------------------------------
configure: error: Please specify the install prefix of iconv with --with-iconv=<DIR>
-----------------------------------------

って言われました。どんどん芋釣で問題出てくる、phpenvあるある。
念のため、iconvもreinstallとパスを通して、以下コマンドで再チャレンジ!

 

!!!解決コマンド!!!!

$ PHP_RPATHS="$(brew --prefix bzip2)" PHP_BUILD_CONFIGURE_OPTS="--with-bz2=$(brew --prefix bzip2) --with-iconv=$(brew --prefix libiconv)"  phpenv install 7.4.9

PHP_RPATHSの指定はなくても良かったかもです🙇‍♂️

\ 🎉7.4系installできたー!🎉 /

[Success]: Built 7.4.9 successfully.
$ phpenv versions
  system
  5.6.1
  7.0.31
  7.1.3
  7.1.30
  7.2.20
  7.3.0
  7.3.7
* 7.4.9 (set by /Users/xxxx/xxxx/.ruby-version)

 

そもそもconfigure optionってなに?

解決できたコマンドは以下ですが、分解して各々の環境変数が何しているか見ていきます。

$ PHP_RPATHS="$(brew --prefix bzip2)" PHP_BUILD_CONFIGURE_OPTS="--with-bz2=$(brew --prefix bzip2) --with-iconv=$(brew --prefix libiconv)"  phpenv install 7.4.9

・PHP_RPATHS

PHP_RPATHS="$(brew --prefix bzip2)" 

そもそもRPATHってなに!?

https://stackoverrun.com/ja/q/2196869 より

-rpath=dir
Add a directory to the runtime library search path. ….

訳)実行中ライブラリの検索パスにディレクトリを追加します。

\ runtime path=rpathってこと?  runtimer? /

 

wikipediaさん(https://en.wikipedia.org/wiki/Rpath)にも同じようなことが書いてある👀

configure optionにも--disable-rpathというオプションがあって、以下のような記述がされていたので、なんか解釈あってそう。

–disable-rpath

実行時にライブラリの検索パスを追加できないようにします。

 

 

・PHP_BUILD_CONFIGURE_OPTS

PHP_BUILD_CONFIGURE_OPTS="--with-bz2=$(brew --prefix bzip2) --with-iconv=$(brew --prefix libiconv)"

そのままですが、ビルド時のconfigure optionを指定できるみたいです。

--with-bz2 …bzip2を有効にし、bzip2の場所を指定をします。

--with-iconv …iconvの場所を指定できます。

 

 

参考:

https://qiita.com/kunit/items/c30147f99a48ebb159d5

https://qiita.com/hnw/items/c227d58528c147de15dd

https://www.ritolab.com/entry/211#aj_5_5

 

まとめ

PHP書いてるけど、こういうmake系は全然わかりません😭まだまだです💦

rpath=replace pathなのかと思ってた。

 

Dockerでlocalhostにアクセスできない時に解決した方法。

Dockerの練習をしようと思いnginxをupして、ブラウザ確認したいってなったんですが、localhostで開けませんでした😭

調べてみると私はDocker Toolbox(※現在非推奨)を使っていたため、192.168.99.100ではアクセスできました⚡️

(※Docker Toolboxは非推奨のため、Docker Desktopを使ってとのこと)

Docker Toolbox has been deprecated and is no longer in active development. Please use Docker Desktop instead. See Docker Desktop for Mac and Docker Desktop for Windows.

 

localhostでは、

$ curl localhost
curl: (7) Failed to connect to localhost port 80: Connection refused

でした。

TerminalとDocker Desktop for Macが同期されていない状態でした。Docker ToolboxはVMを立てる方法で、Docker Desktop for Macはlocalhostを使う為こうなったみたいです。

そこで、Docker Toolboxを削除し、Docker Desktop for Macを入れ直すことで、TerminalとDocker Desktop for Macが同期されlocalhostでアクセスできるようになりました🙌🙌🙌

(Docker Desktop と Docker Toolbox の共存は可能のようですが、Docker Toolboxは非推奨なのでアンインストールしました。)

参考:

https://docs.docker.com/docker-for-windows/docker-toolbox/
https://qiita.com/amuyikam/items/ef3f8e8e25c557f68f6a
https://docs.docker.jp/docker-for-mac/docker-toolbox.html

 

Docker Toolboxを使っている時

$ docker-machine ls
NAME      ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER      ERRORS
default   *        virtualbox   Running   tcp://192.168.99.100:2376           v19.03.12
$ docker-machine config default
--tlsverify
--tlscacert="/Users/watashi/.docker/machine/machines/default/ca.pem"
--tlscert="/Users/watashi/.docker/machine/machines/default/cert.pem"
--tlskey="/Users/watashi/.docker/machine/machines/default/key.pem"
-H=tcp://192.168.99.100:2376
$ env | grep DOCKER
DOCKER_HOST=tcp://192.168.99.100:2376
DOCKER_MACHINE_NAME=default
DOCKER_TLS_VERIFY=1
DOCKER_CERT_PATH=/Users/watashi/.docker/machine/machines/default
$ curl http://192.168.99.100/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

 

Docker Desktop for Macを使っている時

Docker Toolboxを削除し、Docker Desktop for Macを入れ直しました。
docker-machineコマンドを削除したので…

$ docker-machine ls
-bash: docker-machine: command not found
$ env | grep DOCKER
# なし

おまけ: 調査で使ったコマンド

ポートが開いてるプロセスの確認

$ lsof -i -P | grep localhost
$ lsof -i -P | grep 192.168.99.100

GASでGET,POSTを受け取る方法

 

久々のGASについてです!

個人的に作りたいアプリが浮かんだので、それを作るためにGASを使うことがあったのでおさらいがてら書きます✏️

参照:https://developers.google.com/apps-script/guides/web

やることはたった3つです!!!

  1. GET,POSTを受け取る関数を書く
  2. 公開する
  3. 動作確認してみる

1. GET,POSTを受け取る関数を書く

引数eでクエリストリングなどの詳細も取得できますー🌱
GETメソッドを受け取る場合

function doGet(e) {
  console.log('getされました');
}

POSTメソッドを受け取る場合

function doPost(e) {
  console.log('postされました');
}

2. 公開する

これをしないと、実際にこのGASにアクセスするURLが発行されません💦

  • ファイル > 版を管理…より説明文を適当に書いてバージョンをSave new version→OKします。
    (最初はバージョン1で保存されると思います。)
  • 公開 > ウェブアプリケーションとして導入 より、project versionを↑で保存したバージョンに、
    Execute the app as(アプリの実行方法)、Who has access to the app(アプリにアクセスできるユーザー)を選択し、「更新」を押下します。
  • Current web app URLが発行されます🚀
    このURLにリクエストすることで、1で作った関数が実行されるようになります。

3. 動作確認してみる

Talend API Testerを使って、リクエストしてみます。
「METHOD」を選んで、2で発行されたURLを貼り付けて、「Send」するだけです。
200が返ってきたので、いい感じそうです🍻

GASのログも確認してみましょう👀(表示 > ログ > App Scriptダッシュボード)

まとめ

個人的に、
Execute the app as(アプリの実行方法)、Who has access to the app(アプリにアクセスできるユーザー)の設定どうするかが気になりました。
個人で使うものであれば、「自分だけ(only myself)」がアクセスできて、「自分(me)」が実行でいいかなと思います。

 

「Write your first Flutter app, part 1」をしてみる!

 

最近よくみるFlutterでHello Worldしてみる

前回はFlutterを使ってHelloWorldをしたので、今回は。。。

Flutterの公式ドキュメントより、初めてのアプリを作ってみますー。わたしなりに日本語訳したのでお役に立てば嬉しいです^^

参照:
https://flutter.dev/docs/get-started/codelab

 

 

GithubにStepごとにプルリク分けたので良かったら参考にしてください。

https://github.com/kin29/flutter_first_app/pulls?q=is%3Apr+is%3Aclosed+

(おさらい)

ちょっと忘れかけていたので、appの新規作成とsimulatorでの実行方法をおさらいしておきます。分かる人は飛ばしてください😅

appの作成

$ flutter create myapp
$ cd myapp

simulatorを起動させておく

$ flutter emulators
2 available emulators:


Galaxy_Nexus_API_29 • Galaxy Nexus API 29 • Google • android
apple_ios_simulator • iOS Simulator       • Apple  • ios

To run an emulator, run 'flutter emulators --launch '.
To create a new emulator, run 'flutter emulators --create [--name xyz]'.

You can find more information on managing emulators at the links below:
  https://developer.android.com/studio/run/managing-avds
  https://developer.android.com/studio/command-line/avdmanager
$ flutter emulators --launch apple_ios_simulator

↑でapple_ios_simulatorが起動しますー

appのrun

simulatorを起動させておいた状態で、

$ flutter devices
1 connected device:

iPhone 11 • E1B5593C-D161-43EC-BD9D-733A9DC10494 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-4 (simulator)
$ flutter run
Launching lib/main.dart on iPhone 11 in debug mode...

Running Xcode build...

 └─Compiling, linking and signing...                        75.9s
Xcode build done.                                           100.4s
Syncing files to device iPhone 11...                               182ms

Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
An Observatory debugger and profiler on iPhone 11 is available at: http://127.0.0.1:49386/TQwM5vCq3BY=/

simulatorに作ったappが起動しますー

では早速、はじめてのアプリを作っていきます🍻

 

Step 1: Create the starter Flutter app

lib/main.dartを以下に書き換える

// Copyright 2018 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

  • リターンしているMaterial(App)とは…?
    モバイルおよびWebの標準であるビジュアルデザイン言語で、Flutterには、いろんなマテリアルウィジェットのセットが用意されているらしい。
  • Statelessウィジェットを拡張している(Step3でStatefulウィジェットを使います)Flutterでは、配置、パディング、レイアウトなど、ほとんどすべてがウィジェットらしい。
  • Material(App)の中のScaffoldウィジェットは、デフォルトのアプリバー、タイトル、およびホーム画面のウィジェットツリーを保持するbodyプロパティを提供する。
  • ウィジェットの主な仕事は、ウィジェットを他の低レベルのウィジェットで表示する方法を説明するbuild()メソッドを提供する。
  • この例のbodyは、Text子ウィジェットを含むCenterウィジェットで構成されていて、 Centerウィジェットは、ウィジェットサブツリーを画面の中央に配置する。

Step 2: Use an external package

外部パッケージを使う例。pub.devにあるパッケージを使うことができる様子。
今回は例として「english_words」というパッケージを追加する。

2-1. pubspec.yamlの依存リストに追加する

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
...
+ english_words: ^3.1.0

2-2. pub get(package get?) をする

Android Studioのpub getをすると、$ flutter pub getが走るっぽい。
これが完了すると、pubspec.lockにもenglish_wordsの依存バージョン情報が追記される。

小ネタ

Waiting for another flutter command to release the startup lock…
がでる時の解決策

$ flutter pub get
Waiting for another flutter command to release the startup lock...

flutterコマンドのcacheにlockfileがあるのが原因らしいので、
/flutter/bin/cache/lockfileをrmすると解決しましたー🙇‍♂️ありがたい
参考:https://qiita.com/konifar/items/29f2ed4bcc2a970014c1

2-3. lib/main.dartに追加したパッケージ(english_words)を取り込む

lib/main.dart

  import 'package:flutter/material.dart';
+ import 'package:english_words/english_words.dart';

2-4. english_wordsを使うコードを書く

lib/main.dart

               Widget build(BuildContext context) {            
+                final wordPair = WordPair.random();            
                 return MaterialApp(            
                   title: 'Welcome to Flutter',            
                   home: Scaffold(              
                       title: Text('Welcome to Flutter'),            
                     ),            
                     body: Center(            
-                      child: Text('Hello World'),            
+                      child: Text(wordPair.asPascalCase),            
                     ),            
                   ),            
                 );

ランダムに英語の単語がキャメルケースで表示されるようになりました!
hot reload⚡️すると単語が変わるのがわかりますー

 

Step 3: Add a Stateful widget

今の状態はStatelessウィジェットで、その名の通り不変なためプロパティの変更ができないためStatefulウィジェットを追加しますー
Statefulウィジェットは、ウィジェットの有効期間中の変化を維持できるらしいですー
Statefulウィジェットの実装には、StatefulWidgetクラスとStateクラスが必要らしい。
StatefulWidgetクラス自体は不変だが、Stateクラスが有効期間中の変化を維持してくれるらしい。

今後、Stateクラスを作るRandomWordsのStatefulウィジェットを追加し、そのRandomWordsを既存のMyAppステートレスウィジェット内の子として使用します。

3-1. main.dartにRandomWordsStateクラスを作成する

lib/main.dart

+ class RandomWordsState extends State<RandomWords> {
+   // TODO Add build() method
+ }

State<RandomWords>はRandomWordsでの使用に特化した汎用のStateクラスを使用していることを示してるらしい。
アプリのロジックと状態のほとんどはStateにあり、RandomWordsウィジェットの状態を維持する。
このクラスは、3-2(スクロールにしたがって無限に生成したランダム単語を保存したり、単語をお気に入り登録したりする機能)で使う。

3-2. statefulなRandomWordsウィジェットをmain.dartに追加する

RandomWordsウィジェットは、Stateクラスを作成する以外にほとんど何もしません。

lib/main.dart

+ class RandomWords extends StatefulWidget {
+   @override
+   RandomWordsState createState() => RandomWordsState();
+ }

3-3. RandomWordsStateクラスのbuildメソッドを追加する

class RandomWordsState extends State {
+ @override
+ Widget build(BuildContext context) {
+   final wordPair = WordPair.random();
+   return Text(wordPair.asPascalCase);
+ }
}

3-4. MyAppから単語生成の部分のコードを取り除いて、statefulなRandomWordsウィジェットを使うようにする

lib/main.dart

class MyApp extends StatelessWidget { 
  @override 
  Widget build(BuildContext context) { 
-   final wordPair = WordPair.random(); 
    return MaterialApp( 
      title: 'Welcome to Flutter', 
      home: Scaffold( 
        title: Text('Welcome to Flutter'), 
        ... 
        body: Center( 
-         child: Text(wordPair.asPascalCase), 
+         child: RandomWords(), 
        ),
      ), 
    );
  } 
}

hot reload⚡️してもsimulatorのアプリはstep2と変わらないことを確認します。

Step 4: Create an infinite scrolling ListView

RandomWordsStateを修正して、単語リストを生成・表示する機能を追加する。
リストにListViewウィジェットを使い、ListViewのビルダーファクトリコンストラクターを使用すると、オンデマンドで遅延してリストビューを作成できるらしい。

4-1. 単語を保存する_suggestionsリストとフォントサイズを大きくする_biggerFont変数をRandomWordsStateクラスに追加する。

lib/main.dart

class RandomWordsState extends State {
+  final _suggestions = [];
+  final _biggerFont = const TextStyle(fontSize: 18.0);
  // ···
}

Unlike Java, Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore (_), it’s private to its library. For details, see Libraries and visibility.

「_」をつけると、dartではprivateになるらしい。

次に、RandomWordsStateクラスに単語リストを表示するListViewをbuildするbuildSuggestions()メソッドを作る。

4-2and4-3. RandomWordsStateクラスに_buildSuggestions(),_buildRow()を追加する

lib/main.dart

Widget _buildSuggestions() {
  return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: /*1*/ (context, i) {
        if (i.isOdd) return Divider(); /*2*/

        final index = i ~/ 2; /*3*/
        if (index >= _suggestions.length) {
          _suggestions.addAll(generateWordPairs().take(10)); /*4*/
        }
        return _buildRow(_suggestions[index]);
      }
    );
}
Widget _buildRow(WordPair pair) {
  return ListTile(
    title: Text(
      pair.asPascalCase,
      style: _biggerFont,
    ),
  );
}
  • /*1*/
    itemBuilderは単語が提案されるたびにコールバックされ、
    偶数行で、その単語をListTileの行に追加する。
    奇数(isOdd)行では、視覚的に分離するための1pxのDividerウィジェットを追加する。
  • /*4*/
    もし単語リスト_suggestionsの単語の数が上限に達したら、さらに10コの単語を生成しリストに追加する。

4-4. RandomWordsStateクラスbuild()メソッドで_buildSuggestions()を使うようにする。

lib/main.dart

@override
Widget build(BuildContext context) {
+  return Scaffold(
+    appBar: AppBar(
+      title: Text('Startup Name Generator'),
+    ),
+    body: _buildSuggestions(),
+  );
}

4-5. MyAppクラスのbuild()メソッドのtitleを変更し、RandomWordsウィジェットをhome直下に移動させる

lib/main.dart

class MyApp extends StatelessWidget {            
  @override            
  Widget build(BuildContext context) {         
    return MaterialApp(                        
      title: 'Startup Name Generator',            
      home: RandomWords(),                       
    );            
  }
}

 

最後に

つぎはPart2で、スクロールとお気に入り登録機能を追加します!がんばりまーす🙌

最近よくみるFlutterでHello Worldしてみる

 

外出自粛GW暇ですねー、なのでFlutter触ってみることにしました💡
フラッターて読むんですかね、フルッターてずっと読んでました。

参考:
https://flutter.dev/docs/get-started/install/macos
https://apps-gcp.com/cloud-pub-sub-dead-letter-topic/

環境構築

入れるものがまあまあ多い印象ですが、思ったよりはすぐできました。

私の環境

  • macOS Catalina 10.15.4
  • Xcodeは古いのは入ってた(今回バージョン最新にしました)
  • Android Studioは入ってない

したこと

https://flutter.dev/docs/get-started/install/macos
ほぼ、↑の通りにしました。英語は優しいので導入しやすかったです。

  • Flutter SDKの導入
  • Xcodeを最新の11にupdate
  • iOS Simulatorのset up
  • Android Studioのインストール
  • Android Emulatorのset up ←ちゃんとできてないかも…
  • VSCode ←AndroidStudioがあればコードかけるけど念のため入れた

 

Flutter SDKの導入

GitからFlutterSDKをゲット
git clone https://github.com/flutter/flutter.git -b stable
私はbashを使っているので、~/.bash_profileを編集して、flutterコマンドのパスを通す。(source 忘れないように!)

確認してみる。

$ flutter --version
Flutter 1.12.13+hotfix.9 • channel stable • git://github.com/flutter/flutter.git
Framework • revision f139b11009 (5 weeks ago) • 2020-03-30 13:57:30 -0700
Engine • revision af51afceb8
Tools • Dart 2.7.2
...
Xcodeのアップデート

itunesから最新Xcodeにアップデートして、以下のコマンドでrunしてlisenceに同意する。

$ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
Password:
$ sudo xcodebuild -runFirstLaunch


You have not agreed to the Xcode license agreements. You must agree to both license agreements below in order to use Xcode.

Hit the Return key to view the license agreements at '/Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf'

Xcode and Apple SDKs Agreement

PLEASE SCROLL DOWN AND READ ALL OF THE FOLLOWING TERMS AND CONDITIONS CAREFULLY BEFORE USING THE APPLE SOFTWARE OR APPLE SERVICES.  THIS IS A LEGAL AGREEMENT BETWEEN YOU AND APPLE.  IF YOU AGREE TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS, CLICK THE “AGREE” BUTTON.  BY CLICKING “AGREE” OR BY DOWNLOADING, USING OR COPYING ANY PART OF THIS APPLE SOFTWARE OR USING ANY PART OF THE APPLE SERVICES, YOU ARE AGREEING ON YOUR OWN BEHALF AND/OR ON BEH
...

By typing 'agree' you are agreeing to the terms of the software license agreements. Type 'print' to print them or anything else to cancel, [agree, print, cancel] agree

You can view the license agreements in Xcode's About Box, or at /Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf

Install Started
1%.........20.........40.........60.........80.........Install Succeeded
iOS Simulatorのセットアップ

以下コマンドでiOS Simulatorを開く
open -a Simulator
File > Open Device より適当なデバイスを選んで、開いて確認してみる。

Flutter アプリを作成してみる

flutter runをすると、さっき開いていたiOS Simulatorに、作成したmy_app_flutterが開きました。

$ flutter create my_app_flutter
$ cd my_app_flutter
$ flutter run

Launching lib/main.dart on iPhone 11 Pro in debug mode...
Running Xcode build...

 ├─Assembling Flutter resources...                           9.0s
 └─Compiling, linking and signing...                         6.3s
Xcode build done.                                           21.8s
Syncing files to device iPhone 11 Pro...
 5,738ms (!)

🔥  To hot reload changes while running, press "r". To hot restart (and rebuild state), press "R".
An Observatory debugger and profiler on iPhone 11 Pro is available at: http://127.0.0.1:61543/7ohrboNLAIo=/
For a more detailed help message, press "h". To detach, press "d"; to quit, press "q".

「Hello world」してみる

Editorは、Android Studioを使いました。

my_app_flutter/lib/main.dart

import 'package:flutter/material.dart';

void main() {
 runApp(App());
}

class App extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     home: Scaffold(
       body: Center(child: Text("hello world")),
     ),
   );
 }
}

上記に書き換えて、既にiOS Simulatorを開いている状態では、
⚡️マークのhot reloadをすると、runしなくても更新してくるようです。

できたー!

 

最後に

Android Emulatorもいれたので、試したかったんですがMacユーザのためAndroidの操作法がわからず🤔
と思ったら、AndroidでもEmulatorできましたー!(ヘッダーとフッターは追加しました。)

次は何かできるアプリを作成したいです!!!

Symfony installerを削除して、Symfony CLI(symfonyコマンド)を入れて使ってみる!

 

お久しぶりです☺️

Symfonyを使っているにもかかわらず、symfonyコマンド使ってないなー
と今更感じたので、この記事を書きます。

 

はじめに

私の場合、Symfony2,3で使っていたSymfony installerを削除する必要がありました。
symfonyというコマンド名でバッテングしてるので、Symfony4からdepricatedになったSymfony installerを削除→Symfony CLIをインストールという手順をしました。
(※ composerを使えば良い話なんですが、symfonyコマンド使ってみたかったので)

Symfony installerが入っている状態

$ symfony

Symfony Installer (1.5.11)
==========================

This is the official installer to start new projects based on the
Symfony full-stack framework.
...

 

ここで、symfony new でプロジェクトを作成しようとすると、
Symfony InstallerはSymfony4から互換性(compatible)なくなったよーって言われました。
また、Symfony4から代わりにcomposer create-project symfony/skeleton [my_project_name]を使ってねーって言ってます。

$ symfony new my_project
PHP Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? in phar:///usr/local/bin/symfony/vendor/guzzlehttp/ringphp/src/Client/CurlFactory.php on line 363
PHP Stack trace:

...

[RuntimeException]
The Symfony Installer is not compatible with Symfony 4.x or newer versions.
Run this other command to install Symfony using Composer instead:
composer create-project symfony/skeleton my_project

一瞬、Symfony4からsymfonyコマンドなくなった?って思いましたが、Symfony4.4のBestPracticeでしっかり使っているので、少し混乱しました😅
参考:

 

SymfonyInstallerを削除して、SymfonyCLIをinstallする。

あまり良くない消し方な気がしますが、以下の方法でSymfonyInstallerを消しました。

$ ls -al ~/.symfony
total 0
drwxr-xr-x 3 watashi staff 96 4 4 20:51 .
drwxr-xr-x+ 118 watashi staff 3776 4 20 18:45 ..
drwxr-xr-x 3 watashi staff 96 4 21 09:23 bin
$ ls -al /usr/local/bin/symfony
-rwxr-xr-x 1 watashi staff 246243 7 4 2019 /usr/local/bin/symfony
$ rm -rf ~/.symfony
$ rm -rf /usr/local/bin/symfony
$ symfony -V
-bash: /usr/local/bin/symfony: No such file or directory

そして、SymfonyCLIをインストールします🚀

$ curl -sS https://get.symfony.com/cli/installer | bash
Symfony CLI installer

Environment check
[*] cURL is installed
[*] Gzip is installed
[*] Git is installed
[*] You architecture (amd64) is supported

Download
Finding the latest version (platform: "darwin_amd64")...
Downloading version 4.14.1 (https://github.com/symfony/cli/releases/download/v4.14.1/symfony_darwin_amd64.gz)...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 636 100 636 0 0 1311 0 --:--:-- --:--:-- --:--:-- 1311
100 7909k 100 7909k 0 0 878k 0 0:00:09 0:00:09 --:--:-- 1443k
Uncompress binary...
Making the binary executable...
Installing the binary into your home directory...
The binary was saved to: /Users/watashi/.symfony/bin/symfony

The Symfony CLI v4.14.1 was installed successfully!

Use it as a local file:
/Users/watashi/.symfony/bin/symfony

Or add the following line to your shell configuration file:
export PATH="$HOME/.symfony/bin:$PATH"

Or install it globally on your system:
mv /Users/watashi/.symfony/bin/symfony /usr/local/bin/symfony

Then start a new shell and run 'symfony'

$ mv /Users/watashi/.symfony/bin/symfony /usr/local/bin/symfony

うぉー!Symfony CLIが入りましたー!!! 🎉

$ symfony
Symfony CLI version v4.14.1 (c) 2017-2020 Symfony SAS
Symfony CLI helps developers manage projects, from local code to remote infrastructure

These are common commands used in various situations:

Work on a project locally

new Create a new Symfony project
serve Run a local web server
server:stop Stop the local web server
security:check Check security issues in project dependencies
composer Runs Composer without memory limit
console Runs the Symfony Console (bin/console) for current project
php, pecl, pear, php-fpm, php-cgi, php-config, phpdbg, phpize Runs the named binary using the configured PHP version

Manage a project on Cloud

login Log in with your SymfonyConnect account
init Initialize a new project using templates
link Link current git repository to a SymfonyCloud project
projects List active projects
envs List environments
env:create Create an environment
tunnel:open Open SSH tunnels to the app's services
ssh Open an SSH connection to the app container
deploy Deploy an environment
domains List domains
vars List variables
user:add Add a user to the project

Show all commands with symfony help,
Get help for a specific command with symfony help COMMAND.

 

Symfony CLIを使ってみる

プロジェクトを作成してみます。
今回は、webアプリケーションを作ってみます。
composer create-project symfony/website-skeleton [project_name]git initをしていることがわかります。

$ symfony new symfony_command_test_web_app --full
* Creating a new Symfony project with Composer
  (running /usr/local/bin/composer create-project symfony/website-skeleton /Users/watashi/symfony_command_test_web_app)

* Setting up the project under Git version control
  (running git init /Users/watashi/symfony_command_test_web_app)


 [OK] Your project is now ready in /Users/watashi/symfony_command_test_web_app


 

symfony server:startを使ってローカルサーバを立てて、ブラウザを確認してみると…いい感じにSymfony5.0.8のwelcomeページが表示されましたー!🍺

$ symfony server:start

 [WARNING] run "symfony server:ca:install" first if you want to run the web server with TLS support, or use
 "--no-tls" to avoid this warning


Apr 29 11:13:01 |DEBUG| PHP    Reloading PHP versions
Apr 29 11:13:01 |DEBUG| PHP    Using PHP version 7.3.11 (from default version in $PATH)
Apr 29 11:13:01 |INFO | PHP    listening path="/usr/sbin/php-fpm" php="7.3.11" port=55287
Apr 29 11:13:01 |DEBUG| PHP    started
Apr 29 11:13:01 |INFO | PHP    'user' directive is ignored when FPM is not running as root
Apr 29 11:13:01 |INFO | PHP    'group' directive is ignored when FPM is not running as root
Apr 29 11:13:01 |INFO | PHP    fpm is running, pid 3483
Apr 29 11:13:01 |INFO | PHP    ready to handle connections

 [OK] Web server listening
      The Web server is using PHP FPM 7.3.11

      http://127.0.0.1:8000

 

symfony server:ca:installをしたら、TLSで確認できるらしいので、入れてみる🔐
を「https://」になったー!ブラウザもちゃんとみれる👀

$  symfony server:start
Apr 29 11:29:01 |DEBUG| PHP    Reloading PHP versions
Apr 29 11:29:02 |DEBUG| PHP    Using PHP version 7.3.11 (from default version in $PATH)
Apr 29 11:29:02 |INFO | PHP    listening path="/usr/sbin/php-fpm" php="7.3.11" port=55368
Apr 29 11:29:02 |DEBUG| PHP    started
Apr 29 11:29:02 |INFO | PHP    'user' directive is ignored when FPM is not running as root
Apr 29 11:29:02 |INFO | PHP    'group' directive is ignored when FPM is not running as root
Apr 29 11:29:02 |INFO | PHP    fpm is running, pid 12395
Apr 29 11:29:02 |INFO | PHP    ready to handle connections

 [OK] Web server listening
      The Web server is using PHP FPM 7.3.11

      https://127.0.0.1:8000

 

さいごに

今までは、composerでプロジェクトを作って、php -S 127.0.0.1:8880 -t public/でブラウザ確認をしていたので、symfonyコマンドの方が短いので使って楽したほうがいいなーと思いました。

 

SpotifyAPIを使いプレイリストを簡単に作成してくれるツールDJ-Kin29リニューアルしました!

以前に作成した、アーティスト名を入力するだけでいい感じのSpotifyプレイリストを作成してくれるツールDJ-Kin29を改良しました!

是非、使ってみてください!!!
https://dj-kin29.herokuapp.com/

今回の改良にあたって、認可フローを見直しました。
前回の記事でまとめたので、よかったら参考にしてください。
SpotifyWebAPIの認可フローをまとめてみた

Githubも公開しまーす。
コントリビュート待ってます🍺
https://github.com/kin29/dj-kin29

Before

  • プレーンなPHP
  • Spotify認可のタイミングがフォームを入力後というおかしなタイミング
入力フォーム (index.php)
↓
↓ 作成 (旧:action先=create.php)
↓
(spotifyの認可画面)
redirect_uri: https://dj-kin29.herokuapp.com/create.php
→ 拒否されたら、 https://{redirect_uri}?error=access_denied
↓
↓ 許可されたら、
↓
プレイリスト作成成功
プレイリスト作成完了画面 (complete.php)
or
プレイリスト作成失敗
プレイリスト作成失敗画面 (failed.php)
↓
↓ more create / retry
↓
入力フォーム (index.php)に戻る

After

  • Symfony4を使用
  • Spotify認可のタイミングを、フォーム入力前にした。
1. / (クエリパラメータにcode=xxxを含まない)
- 「Authorization to Spotify」ボタンで、Spotifyとの連携(認可)をスタートする。(リンク先:/auth_spotify)
※ボタン押さずとも連携スタートさせたかったけど、spotify側の認可URLにリダイレクトさせてたらTwitterカードPreviewでエラーになったので、やめました😓

2. /auth_spotify
- Spotifyの認可がスタートする
  - 認可を許可したことがある場合:リダイレクトURL (/code=xxx)に遷移する。
  - 許可していない場合:Spotifyログイン画面 or 認可しますか画面に遷移する。
    - 認可の許可をした場合:/code=xxxにリダイレクトする。
    - 認可を拒否した場合:/error=xxx(エラーページ)にリダイレクトする。(→Re-Tryボタンで再チャレンジ可能)

3. /code=xxx
- フォーム画面。post先は、/create。

4. /create
- SpotifyWebAPIを使って、プレイリストを作成する。
  - 作成成功した場合;完了画面
  - 作成失敗した場合;失敗画面(→Re-Tryボタンで再チャレンジ可能)
- 「More create」ボタンでさらにプレイリスト作成可能(2に戻る)

さいごに

  • Tweetボタン設置しました^^
  • GAを充実させたくて、GTMと格闘しました。
  • 引き続きherokuを使っているので、初動に時間がかかります、、、🙇‍♂️
  • アーティスト名検索では、該当するアーティストの一番上だけを取得し、それに紐付く曲を取得するので、アーティスト名が被っていると期待したプレイリストができないことがあります、、、🙇‍♂️
    (日本のガールズバンドHumpBackのつもりで入力したところ、まだサブサクは解禁してないようで、違うバンドの曲が入っていました。)