symfony.lockとは?

 

symfonyを使ってるといつの間にか入ってて、更新もされるsymfony.lock。
composer.lockと何が違うのか等、よくわかってなかったので自分なりに調べたことをまとめます。

 

\いろいろまとめてみたんですが、すでに記事ありました!/
こちらの方が断然わかりやすいです!!!
https://zenn.dev/ttskch/articles/13013224b61531

 

symfony.lockには何が書いてある?

composer require symfony/<name> などのコマンドを叩いた時に、必要な環境変数(.env)やconfig/のyamlの追加が自動的にされることがあります。
この履歴がsymfony.lockに記録されています。
doctrine/annotationsといったsymfony/<name>以外の対象もあります。

ちなみに、
composer require symfony/notifierをした時、「config/packages/notifier.yamlを追加する」といった定義(レシピ)はsymfony/recipesによって管理されています。

さらに、
「config/packages/notifier.yamlを追加する」という定義(レシピ)の実行は、symfony/flex(Composer Plugin for Symfony)によって行われています。

composer.lockとの違いは?

  • symfony/recipesに置いてあるどのバージョン(version)のmanifest(レシピの定義)を使っているのかが明記されています。
  • 追加や更新するファイル(files)についても明記されています。
// symfony.lock
{
    "symfony/flex": {
        "version": "2.3",
        "recipe": {
            "repo": "github.com/symfony/recipes",
            "branch": "main",
            "version": "1.0",
            "ref": "146251ae39e06a95be0fe3d13c807bcf3938b172"
        },
        "files": [
            ".env"
        ]
    },
    "symfony/notifier": {
        "version": "6.3",
        "recipe": {
            "repo": "github.com/symfony/recipes",
            "branch": "main",
            "version": "5.0",
            "ref": "c31585e252b32fe0e1f30b1f256af553f4a06eb9"
        },
        "files": [
            "config/packages/notifier.yaml"
        ]
    }
}
// composer.lock
    ...
    "packages": [
        {
            "name": "symfony/flex",
            "version": "v2.3.1",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/flex.git",
                "reference": "3c9c3424efdafe33e0e3cfb5e87e50b34711fedf"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/flex/zipball/3c9c3424efdafe33e0e3cfb5e87e50b34711fedf",
                "reference": "3c9c3424efdafe33e0e3cfb5e87e50b34711fedf",
                "shasum": ""
            },
            "require": {
                "composer-plugin-api": "^2.1",
                "php": ">=8.0"
            },
            "require-dev": {
                "composer/composer": "^2.1",
                "symfony/dotenv": "^5.4|^6.0",
                "symfony/filesystem": "^5.4|^6.0",
                "symfony/phpunit-bridge": "^5.4|^6.0",
                "symfony/process": "^5.4|^6.0"
            },
            "type": "composer-plugin",
            ...

symfony.lockはsymfony/flexをrequireすると追加される

symfony/flex => Composer plugin for Symfony

$ composer require symfony/flex
...
// ↓↓↓ この辺りがsymfony/flexによって行われている。 ↓↓↓

Symfony operations: 1 recipe (ad5e8d2058412a4be7bb46bf8d4af76c)
  - Configuring symfony/flex (>=1.0): From github.com/symfony/recipes:main

// ↑↑↑ この辺りがsymfony/flexによって行われている。 ↑↑↑

No security vulnerability advisories found
Using version ^2.3 for symfony/flex


$ git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git restore ..." to discard changes in working directory)
    modified:   composer.json

Untracked files:
  (use "git add ..." to include in what will be committed)
    .env
    composer.lock
    symfony.lock

no changes added to commit (use "git add" and/or "git commit -a")

 

どうなったらsymfony.lockに追加や更新されるか?

symfony/flexがinstall済みで、かつsymfony/recipesで管理されているcomposerパッケージについてcomposer requirecomposer updateをした時のようです。

また、レシピがないパッケージについても以下コマンドでsymfony.lockに追加できます。さらに、既にsymfony.lockに定義されているパッケージについてのバージョンを更新できます。

$ composer recipes:install <vendor>/<package> --force -vた

ただ、レシピがないのにsymfony.lockに定義してるパッケージは何の意味があるのかよくわかっていません🤔 誰か教えてください!

最後に

この記事を書くために、symfony/flexを読みました。Composer pluginの作り方や流れを知ることができたので次の記事で書こうと思います。

参考

PHPカンファレンス福岡2023行ってきたよ

 

2023/06/24にPHPカンファレンス福岡2023に行ってきました。

2018年ぶりの参加でした!!!
https://phpcon.fukuoka.jp/2023

 

すっごい人の色んなお話を聞けて超超超刺激になりました!
さらに色んな人と知り合えたり、懐かしい人と会えたりできたので超楽しかったです🙌
無限LTしたかったけど勇気なかったです…
「参加したならLTくらいしないともったいない」ってすっごい言われて、そうだよなーもったいないことした・・・ってなってます😭
次カンファレンス行く時は登壇予定なくてもLT用意する(目標

## メモ

Symfony6.3のおすすめ機能

– WebhookをController使わずに作れるようになった。 https://symfony.com/blog/new-in-symfony-6-3-webhook-and-remoteevent-components
– service.yamlに書いてたサービス定義を、ほぼAttributeだけでできるようになった。 https://symfony.com/blog/new-in-symfony-6-3-dependency-injection-improvements#using-autowiring-to-generate-closures
– メソッドをDIできるようになった https://symfony.com/blog/new-in-symfony-6-3-dependency-injection-improvements#using-autowiring-to-generate-closures

ref: https://symfony.com/blog/symfony-6-3-curated-new-features

 

お昼ご飯🍚

牧のうどん、うまいけど食べるの遅いと無限に増えた。
九州のやわやわうどん、すき。

お腹いっぱいで眠くなったけど、コーヒー飲み放題で助かりました🙏☕️🙏

 

夜ご飯🍚

たのしかったーーーー

みんなが幸せなら幸せ教に入信しそうuuu

まとめ

福岡またいきたいです!次はついでに実家でゆっくりできたら良い。
次は新幹線でいきたい、7千円の充電式ヘアブラシ没収された&セントレアまで遠いので。次は、ホテルさっさとチェックインしておく。

スタッフさん登壇者さんスポンサーさん参加者さん不参加だけど絡んでくださった皆様ありがとうございましたー!

↑天神から祇園のホテルまで酔っ払いながら帰った朝に撮った写真

PHPerKaigi2023参加レポ〜iwillblog〜

タイムテーブルはこちら。

https://fortee.jp/phperkaigi-2023/timetable

PHPerKaigi2023の私的状況

  • Day0、Day1 オンライン参加
  • Day2 オフライン参加 (子供を預けることに成功、こだまグリーン車早割の往復、懇親会もあるので一泊)
  • ペンライト羨ましくて、次はLTしたいと思いました。
  • ちょうぜつ本が当たった😍(既に購入済み)
  • 今年もノベルティ最高!
    • GMOさんの湯呑み良き(写真に入れ忘れた)
    • 顔パック、遠征先で化粧水がわりになったのでありがたいです!

Day0

#### PHPUnit 10 概論

https://github.com/sebastianbergmann/phpunit/blob/10.0.0/ChangeLog-10.0.md

ChangeLogをみてもRemovedが多いので、安易にupdateしにくいなとい印象でした。

差別的用語をなくした件を知って、最近whiteListという変数を作ってしまった自分を反省しました!参考にさせてもらいます!

  • blackList -> ExcludeList
  • whiteList -> filter

また、デフォルトでDeprecation, Notices, Warnings, Skippedの件数を表示しなくなるっていうのは地味に嫌なので、phpunit.xmlの設定する必要があるなということを忘れないようにしたいなと思いました。

DataProviderはよく使ってるので、仕様変更に対応しなければ 🤯

以下の条件に当てはまるDataProviderが非推奨になりました。
● staticではない
● publicではない
● 引数を必要とする
逆にいえば、以下のような形式のDataProviderを推奨しているということですね。
public static XXX() {} 

Day1

#### Composerを「なんとなく使う」から「理解して使う」になる

はい!なんとなく使ってました。思ってた通りで安心してましたが、パッケージ更新したい時にupdate?require?となることがあるのでこの表はめちゃ重宝させてもらいます🙇🙇🙇

  • composer require {package-name}composer.json/composer.lock共に更新される
  • composer update {package-name}→あくまでもcomposer.jsonのバージョン指定範囲内で更新する => composer.lockのみ更新
  • =>パッケージ更新したい時、現在のcomposer.jsonのバージョン指定じゃ希望のバージョンにならない時は、requireする必要ある。現在のcomposer.jsonのバージョン指定内の更新で良いならupdate
  • 個人的コマンドメモ
// 何が更新されるかを事前にチェックすることができる
$ composer update --dry-run

// composer.jsonのrequireにないのに依存してcomposer.lockにあるパッケージはどこ依存だ?ってときに使える 
$ composer depends {package-name}

 

Day2

現地参加の特権、アンカンファレンス 🙌

郡山さんのおもしろかった〜

https://alps-asd.github.io/ つかって設計してみたい!

 

### PHPの最高機能、配列を捨てよう!!

現地では裏のそーだいさんの見て、うずらさんのはYouTubeで視聴しました!

たしかにreturn type arrayの時、どんな配列なのか気になって深くコードを読むみたいなのありがちで時間取られちゃうのでもったいないです。

DTOを作ってその配列にするは結構やってたので、安心しました!

懇親会

何年振りかのお酒飲みながらの懇親会たのしかったです^^

 

GASでよく使うけど忘れる系のチートシート〜外部API使う時の系〜

 

以前に、スプシ系のチートシートは作ったんですが、

GASでよく使うけど忘れる系のチートシート〜スプシ系〜

外部API使う時も毎回ググりまくるのでまとめておきます!

スクリプト プロパティ(環境変数)

// スクリプト プロパティの取得
const GITHUB_TOKEN = PropertiesService.getScriptProperties().getProperty('GITHUB_TOKEN');

ref: https://developers.google.com/apps-script/reference/properties?hl=en

API叩く時

const url = 'https://api.github.com/users/kin29/repos';
const option = {
  'method' : 'get',
  'headers': {
      'Accept': 'application/vnd.github+json',
      'Authorization': 'Bearer '+ GITHUB_TOKEN,
      'X-GitHub-Api-Version': '2022-11-28'
  }
};
const response = UrlFetchApp.fetch(url, option).getContentText();
// JSON.parse(response)するとobjectになって使いやすい

ref: https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app

 

やっとUA→GA4に移行したよ【Google Analytics】

 

みなさんもう移行済みでしょうか?わたしはまだでした😅
ということで手順メモ的な感じで書きます。

ユニバーサルアナリティクス(UA)が2023年7月1日にサポート終了
2023 年 7 月 1 日をもって、標準のユニバーサル アナリティクス プロパティにおける新しいヒットの処理は停止されます。

参考にした公式ドキュメント

https://support.google.com/analytics/answer/10110290#zippy=%2C%E3%81%93%E3%81%AE%E8%A8%98%E4%BA%8B%E3%81%AE%E5%86%85%E5%AE%B9

前提

– 対象サイト: ここ(https://kin29.info)
– GTM使ってる。

手順

1.現在使用中のUAプロパティからGA4プロパティを作成する

(プロパティとは?)

2.「設定アシスタント」に沿っていく

プロパティ > 設定アシスタントにて、TODOリスト方式でやること教えてくれるから簡単そう!にみえる….

3.Googleタグの設置(GTMを使うパターン)

参考: https://support.google.com/tagmanager/answer/9442095

3-1.GA4設定タグを設置する

[GA管理画面]データストリーム > ウェブ > ストリームの詳細

測定IDをコピペしておく🥸

[GTM管理画面]GA4設定タグを作成します。

コピペしておいた測定IDを使います。
プレビューしてちゃんとタグが発火することを確認しましょう🔥

3-2.GA4イベントタグを設定する

※今回は「スクロール50%」のイベントですが、各自で必要なイベントで設定してください。

[GTM管理画面]トリガーを作成

– トリガータイプ: スクロール距離
– 縦方向スクロール距離: 割合50%
– このトリガーの発生場所: すべてのページ

[GTM管理画面]GA4イベントタグを作成し、作成したトリガーを配信トリガーにする

– タグの種類: Google アナリティクス: GA4 イベント
– 設定タグ: 3-1で作成したものを選ぶ
– イベント名:scroll_50
※このイベント名は「6.コンバージョンを設定する」で使います。

4.Googleシグナルを有効にする

(Googleシグナルとは?)

5.コンバージョンを設定する

コンバージョン > 新しいコンバージョンイベントから、「4-2.GA4イベントタグを設定する」で作成したイベント名(scroll_50)のイベントを作成します。

リアルタイムの概要より、scroll_50がコンバージョンとして計測されていることが確認できました。

 

必要であれば、オーディエンスを定義・ユーザの管理をします〜。

これでGA4に移行完了しました🎉🍾

注意 🚨

データの収集については、すぐに反映されず、翌日に「データを送受信しています」になりました。おかしいなと思っても、GTMプレビューで発火していることが確認できていれば気長に待つのもありです🙆

 

 

ペチコン2022の参加メモ

 

1日目はオンラン参加で、2日目は現地参加予定しました!

モチベ上がりました!!!開催ありがとうございました🙇
現地でいろんな人に会えて楽しかったです✌️
来年は子供と行くか、それともビール飲みたいから泊まるかしたいなと妄想しております。
帰りのグリーン車からこの記事かいてます(こだま早割でのぞみ指定席より安かった)

タイムテーブル

https://fortee.jp/phpcon-2022/timetable

メモ(箇条書き)

1日目

  • フィーチャートグルよく出てきた!
  • Symfony UX使ってみたい!グラフとかしてみようかな🤔
  • スキーマ駆動開発良さそう
  • 語彙力を増やしたり、良い命名のためにもフレームワーク読んだり使うことが大事

2日目

来年の自分へのメモ

  • 来年は2023/10/08(日)開催予定!
  • 大LT出たい。いつもみてて思う…
  • 京急蒲田は蒲田(JR)ではないよ、品川-京急蒲田は快特が良いよ(各停乗るな)
  • 品川で、出口(JR乗り換え)に行くな、普通の出口に行こう。
  • 泊まりができれば飲めるよ🍺
  • 子供入場できるよ👶
  • 早割こだまグリーン車良い🙆のぞみだと乗り換えの待ちがあるので20分しか変わらなかった。

 

おまけ

Heroku + SendGrid → GAS + Gmail に移行したよ

 

2022/11/28にHerokuのフリープランがなくなるので、
Heroku + SendGridで作っていたものを、GAS + Gmailに移行しました。

実際に移行したのは、過去記事にもまとめたSlackコマンドです。

slackコマンドを作ってみた!

Heroku + SendGrid → GAS + Gmail対応のdiff:
https://github.com/kin29/slack2mail/compare/5ead7fc8f0bccd368c99dd5215e507bd78e38887…2e8bb4af713276237cb3c9a03c33d73be8bbc8bc

GASでGmailを送信する

const toAddress = 'to@example.com';
const title = 'メール件名';
const content = 'メール内容';
const options = {
  'from': 'from@example.com',
};
GmailApp.sendEmail(toAddress, title, content, options);

claspを使って、実装済みのGASをcloneする

$ clasp clone [scriptId]

さいごに

もう1つHerokuのフリープランを使って動かしているアプリがあるので、コレも早く対応したいところではあります…

GASのテスト(Jest)を書く!!!

 

GASを書いていて、テストを書きたくなる時って結構ありませんか?
ただ、なかなか手をつけることができずにテストを書かずにおいてしまい罪悪感が積もりに積もったので、ついにテストを書きました 🎉🍾✨
そのことについてまとめます❕
(TypeScriptはまだまだ勉強中でエセなのでご了承ください🙇)

もくじ

 

準備🎒

npm install -D clasp @types/google-apps-script

$ npm install -D clasp @types/google-apps-script

tsconfig.jsonを追加

$ tsc -init
//tsconfig.json
{
  "compilerOptions": {
    "lib": ["esnext"],
    "experimentalDecorators": true
  }
}

npx clasp create --type standalone --rootDir src

$ npx clasp create --type standalone --rootDir src

// src/appsscript.json と .clasp.json が生成される

// src/appsscript.json
{
  "timeZone": "America/New_York",
  "dependencies": {
  },
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

// .clasp.json
{"scriptId":"xxx","rootDir":"src"}

テストコードはclasp pushする必要がないためsrc/以下にappsscript.jsonを生成しました。

//構成
.
├── README.md
├── node_modules/
│
├── src    ←clasp pushの対象ルートディレクトリ 
│   ├── _utils.ts
│   ├── appsscript.json
│   └── code.ts
│
├── tests ←テストコードのディレクトリ(clasp pushしない)
│   ├── _utils.test.ts
│   ├── date-mock.ts
│   └── gmail-message-mock.ts
│
├── jest.config.js
├── package.json
├── tsconfig.json
└── .clasp.json

npm install -D jest "@types/jest" ts-jest typescript

$ npm install -D jest "@types/jest" ts-jest typescript

jest.config.jsを追加

$ jest --init

参考: https://typescript-jp.gitbook.io/deep-dive/intro-1/jest#suteppu2jestwosuru

//jest.config.js
module.exports = {
  "roots": [
    "<rootDir>"
  ],
  "testMatch": [
    "**/__tests__/**/*.+(ts|tsx|js)",
    "**/?(*.)+(spec|test).+(ts|tsx|js)"
  ],
  "transform": {
    "^.+\\.(ts|tsx)$": "ts-jest"
  },
}

tsconfig.jsonにesModuleInterop=trueを追加

以下のwarningがでたため、言われるがままに”esModuleInterop”: trueを追加しました。

ts-jest[config] (WARN) message TS151001: If you have issues related to imports, you should consider setting `esModuleInterop` to `true` in your TypeScript configuration file (usually `tsconfig.json`)
//tsconfig.json
{
  "compilerOptions": {
    "lib": ["esnext"],
    "experimentalDecorators": true,
+   "esModuleInterop": true,  //追加
  }
}

src/appsscript.jsonのtimeZoneを”Asia/Tokyo”に修正

//src/appsscript.json
{
- "timeZone": "America/New_York",
+ "timeZone": "Asia/Tokyo",
  ...
}

npm testでテスト実行できるようにする

//package.json
{
  ....
+ "scripts": {
+   "test": "jest"
+ }
}

テストを書く📊

GmailMessageのモックを作る

テストできるように、インターフェースGmailMessageを実装してモック(GmailMessageMock)を作成しました。

tests/gmail-message-mock.ts

import GmailMessage = GoogleAppsScript.Gmail.GmailMessage;

export class GmailMessageMock implements GmailMessage {
    constructor(
        private body: string,
    ) {
    }

    getBody(): string {
        return this.body;
    }
    ...
}

tests/_utils.test.ts

import { Utils } from "../src/_utils";
import { GmailMessageMock } from "./gmail-message-mock";

describe('Utils.createBodyMessage', () => {
    test('[body]xxxを生成できること', () => {
        const inputGmailMessage = new GmailMessageMock('テストメッセージです');

        const util = new Utils();
        const actual = util.createBodyMessage(inputGmailMessage);
        expect(actual).toBe('[body]テストメッセージです');
    })
})

src/_utils.ts

export class Utils {
    public createBodyMessage(gmailMessage: GoogleAppsScript.Gmail.GmailMessage): string {
        return "[body]" + gmailMessage.getBody();
    }
}

ついに、テストできるようになりましたー🎉🎉🎉

$ npm test

> test
> jest

 PASS  tests/_utils.test.ts
  Utils.createBodyMessage
    ✓ [body]xxxxを生成できること (2 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.657 s
Ran all test suites.

メモ📝

– GASではimportができないので、読み込み順序をいい感じにするために先に読み込まれる必要があるファイルについては_hoge.tsのようにアンダーバーから始まるファイル名にしました🚨
– clasp pushされるとcode.ts→code.gsに変換されます。

参考にした記事🙇

https://developers.google.com/apps-script/guides/clasp
– https://kotamat.com/post/gas-testing/

最後に

詳細が気になる方は、https://github.com/kin29/line-notify-from-gmailにコミット履歴があるので参考にしてみてください。

(最初yarn使ってたのですが、npmだけでいけそうなので最後にyarn.lockを消したりしてます)

 

symfony/pantherでスクレイピングしてみた(Twitterのエゴサ結果をスクショする)

 

PHPカンファレンス沖縄2022でたつきちさんの発表を見て、

symfony/pantherでスクレイピングしたくなったので使ってみしました!
超簡単でした!!!SymfonyアプリでなくプレーンなPHPでも使えるの良いです🙆

準備

$ composer req symfony/panther
$ composer require --dev dbrekelmans/bdi

Twitterで「kin29.info」を検索し、結果をスクショしてみる(エゴサ)

twitterSearch.php

<?php
use Symfony\Component\Panther\Client;

require __DIR__.'/vendor/autoload.php';

$client = Client::createFirefoxClient();

//Twitterで「kin29.info」を検索
$client->request('GET', 'https://twitter.com/search?q=kin29.info&src=typed_query&f=live');

//読み込みがかかるので、必要なElementができるまで待つようにする
$client->waitForVisibility('section > div[aria-label="タイムライン: タイムラインを検索"]');

//スクショをとる
$client->takeScreenshot('screen.png');

echo 'done';

無事にスクショが撮れましたー🎉
ただ、スクショのサイズが小さいのでフルスクリーンでしたかったですが、やり方がわからず😭

GASでよく使うけど忘れる系のチートシート〜スプシ系〜

GASでよく使うけど忘れるコードを備忘録として残しておきます📝

スプシ取得系

  • 指定セルの中身を取得
  • 指定列(縦)のすべての中身を取得
  • 最後の行を取得
  • 最後の列を取得
//指定セル(シート1のA1)の中身を取得
let value = SpreadSheetObj.getSheetByName('シート1').getRange('A1').getValue();

//指定列(シート1のB列)のすべての中身を取得
let values = SpreadSheetObj.getSheetByName('シート1').getRange("B:B").getValues();

//(シート1の)最後の行を取得
let lastRow = SpreadSheetObj.getSheetByName('シート1').getLastRow();

//(シート1の)最後の列を取得
let lastCol = SpreadSheetObj.getSheetByName('シート1').getLastColumn();

スプシ書き込み系

const OUTPUT_SHEET_ID = 'スプシID'
const datas = ['A列に入れたい文字', 'B列に入れたい文字', 'C列に入れたい文字'];

var SpreadSheetObj = SpreadsheetApp.openById(OUTPUT_SHEET_ID); //アウトプットするシート

//シート 1の最終行の挿入
SpreadSheetObj.getSheetByName('シート1').appendRow([datas[0], datas[1], datas[2]]);

//更新
SpreadsheetApp.flush();

スプシクリア

const targetSheet = SpreadsheetApp.openById(OUTPUT_SHEET_ID).getSheetByName(sheetName);
var deleteRowCount = targetSheet.getLastRow() - 1;
if (deleteRowCount > 0) {
  targetSheet
  .getRange(startRow, startColumn, deleteRowCount, deleteColumnCount)
  .clear();
}

公式リファレンス:
https://developers.google.com/apps-script/reference/spreadsheet/