<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PHP &#8211; エンジニア見習い</title>
	<atom:link href="https://otonan-syusyoku.work/archives/category/learning/php/feed" rel="self" type="application/rss+xml" />
	<link>https://otonan-syusyoku.work</link>
	<description>三流プログラマー</description>
	<lastBuildDate>Tue, 06 Jan 2026 05:28:23 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://otonan-syusyoku.work/wp-content/uploads/2023/10/cropped-名称未設定のデザイン-16-32x32.png</url>
	<title>PHP &#8211; エンジニア見習い</title>
	<link>https://otonan-syusyoku.work</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>エラー通知で消耗してない？例外の「型」で緊急度を自動振り分けする方法</title>
		<link>https://otonan-syusyoku.work/archives/2179</link>
					<comments>https://otonan-syusyoku.work/archives/2179#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Tue, 06 Jan 2026 04:55:26 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=2179</guid>

					<description><![CDATA[前回の記事で、LogicException（バグ）とRuntimeException（環境エラー）の違いについてお話ししました。 「違いはわかったけど、実際の開発でどう役立つの？」 そう思った方もいるかもしれません。 実 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p data-path-to-node="39">前回の記事で、<code data-path-to-node="39" data-index-in-node="7">LogicException</code>（バグ）と<code data-path-to-node="39" data-index-in-node="26">RuntimeException</code>（環境エラー）の違いについてお話ししました。</p>
<p data-path-to-node="40">「違いはわかったけど、実際の開発でどう役立つの？」</p>
<p data-path-to-node="41">そう思った方もいるかもしれません。 実は、この使い分けを徹底すると、<b data-path-to-node="41" data-index-in-node="34">「運用の楽さ」</b> が劇的に変わるんです！</p>
<p data-path-to-node="42">今回は実践編として、<b data-path-to-node="42" data-index-in-node="10">「例外の種類によって、Slack通知やエラー画面を自動で振り分ける方法」</b> をご紹介します。</p>
<p data-path-to-node="42">
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="2179" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">すべてのエラーを通知していませんか？</a></li><li class="rtoc-item"><a href="#rtoc-2">「型」で振り分ける実装パターン</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-3">この設計のメリット</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-4">例外処理は「未来の自分」へのメッセージ</a></li></ol></div><h2 id="rtoc-1"  data-path-to-node="43">すべてのエラーを通知していませんか？</h2>
<p data-path-to-node="44">開発現場でよくあるのが、「エラーが出たら全部Slackに通知！」という運用。 これ、最初はいいんですが、だんだんこうなりませんか？</p>
<ul data-path-to-node="45">
<li>
<p data-path-to-node="45,0,0">深夜に「DB接続タイムアウト」の通知が来て叩き起こされる（でも数秒後に自然復旧してる）</p>
</li>
<li>
<p data-path-to-node="45,1,0">通知が多すぎて、本当に重要なバグ報告を見逃す</p>
</li>
<li>
<p data-path-to-node="45,2,0">結果、<b data-path-to-node="45,2,0" data-index-in-node="3">「通知チャンネル誰も見なくなる」</b> 現象が発生…</p>
</li>
</ul>
<p data-path-to-node="46">これは、<b data-path-to-node="46" data-index-in-node="4">「バグ（緊急）」</b> と <b data-path-to-node="46" data-index-in-node="15">「環境トラブル（要確認）」</b> を混ぜてしまっているのが原因です。</p>
<h2 id="rtoc-2"  data-path-to-node="47">「型」で振り分ける実装パターン</h2>
<p data-path-to-node="48">ここで、前回の知識が活きてきます。 例外ハンドラー（エラーを一元管理するクラス）で、以下のように振り分けてみましょう。</p>
<pre class="line-numbers">use Psr\Log\LoggerInterface;

class AppExceptionHandler
{
    public function __construct(
        private LoggerInterface $logger,
        private SlackNotifier $slack
    ) {}

    public function handle(\Throwable $e): void
    {
        // パターン1：LogicException / DomainException
        // 意味：「コードがおかしい（バグ）」
        if ($e instanceof \LogicException) {
            // これは緊急事態！開発者にすぐ知らせる
            $this-&gt;logger-&gt;critical($e-&gt;getMessage());
            $this-&gt;slack-&gt;send("&#x1f6a8; 緊急: 実装バグが発生！すぐ直して！: " . $e-&gt;getMessage());
            
            // ユーザーには「システムエラー」とだけ表示
            $this-&gt;renderErrorPage(500);
            return;
        }

        // パターン2：RuntimeException
        // 意味：「外部要因で失敗（環境エラー）」
        if ($e instanceof \RuntimeException) {
            // ログには残すけど、深夜に叩き起こすほどではないかも
            $this-&gt;logger-&gt;error($e-&gt;getMessage());
            
            // ユーザーには「現在混み合っています」など、やんわり伝える
            $this-&gt;renderErrorPage(503);
            return;
        }

        // その他の予期せぬエラー
        $this-&gt;logger-&gt;error('Unknown Error: ' . $e-&gt;getMessage());
        $this-&gt;renderErrorPage(500);
    }
}
</pre>
<p>&nbsp;</p>
<h3 id="rtoc-3"  data-path-to-node="50">この設計のメリット</h3>
<p data-path-to-node="51">こうすることで、開発チームの動き方が変わります。</p>
<ol start="1" data-path-to-node="52">
<li>
<p data-path-to-node="52,0,0"><b data-path-to-node="52,0,0" data-index-in-node="0">Slack通知が来たら「即対応」</b></p>
<ul data-path-to-node="52,0,1">
<li>
<p data-path-to-node="52,0,1,0,0"><code data-path-to-node="52,0,1,0,0" data-index-in-node="0">LogicException</code> だけが通知されるので、「通知 = 自分のコードミス」と認識できます。</p>
</li>
</ul>
</li>
<li>
<p data-path-to-node="52,1,0"><b data-path-to-node="52,1,0" data-index-in-node="0">ログが綺麗になる</b></p>
<ul data-path-to-node="52,1,1">
<li>
<p data-path-to-node="52,1,1,0,0">一時的な接続エラーなどはログファイルに溜まるだけなので、精神衛生上とても良いです（もちろん定期的なチェックは必要ですよ！）。</p>
</li>
</ul>
</li>
<li>
<p data-path-to-node="52,2,0"><b data-path-to-node="52,2,0" data-index-in-node="0">ユーザーへの案内が親切になる</b></p>
<ul data-path-to-node="52,2,1">
<li>
<p data-path-to-node="52,2,1,0,0">バグなら <code data-path-to-node="52,2,1,0,0" data-index-in-node="5">500</code>、アクセス過多なら <code data-path-to-node="52,2,1,0,0" data-index-in-node="18">503</code> と、状況に合わせたHTTPステータスコードを返せます。</p>
</li>
</ul>
</li>
</ol>
<h2 id="rtoc-4"  data-path-to-node="53">例外処理は「未来の自分」へのメッセージ</h2>
<p data-path-to-node="54">例外クラスを使い分けることは、単なるルールではありません。</p>
<ul data-path-to-node="55">
<li>
<p data-path-to-node="55,0,0"><b data-path-to-node="55,0,0" data-index-in-node="0">LogicException</b> を投げるときは、「これバグだから絶対直してね！」というメッセージ。</p>
</li>
<li>
<p data-path-to-node="55,1,0"><b data-path-to-node="55,1,0" data-index-in-node="0">RuntimeException</b> を投げるときは、「運用でカバーしてね」というメッセージ。</p>
</li>
</ul>
<p data-path-to-node="56">この意図を込めてコードを書けるようになると、一人前のエンジニアへまた一歩近づけます。 「エラーハンドリング」という地味な部分ですが、こここだわるとカッコいいですよ！</p>
<p data-path-to-node="57">ぜひ、自分たちのプロジェクトにも導入できないか検討してみてくださいね。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/2179/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>とりあえず Exception にしてない？正しい使い分けで「デキる」コードへ</title>
		<link>https://otonan-syusyoku.work/archives/2175</link>
					<comments>https://otonan-syusyoku.work/archives/2175#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Tue, 06 Jan 2026 04:46:19 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=2175</guid>

					<description><![CDATA[「例外処理、なんとなく try-catch で囲って終わり…」 「全部 Exception クラスを使っちゃってるけど、これっていいの？」 PHPを勉強し始めて少し経つと、こんな悩みが出てきませんか？ 実は、僕も最初はそ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p data-path-to-node="5">「例外処理、なんとなく <code data-path-to-node="5" data-index-in-node="12">try-catch</code> で囲って終わり…」</p>
<p data-path-to-node="5">「全部 <code data-path-to-node="5" data-index-in-node="36">Exception</code> クラスを使っちゃってるけど、これっていいの？」</p>
<p data-path-to-node="6">PHPを勉強し始めて少し経つと、こんな悩みが出てきませんか？ 実は、僕も最初はそうでした。</p>
<p data-path-to-node="7">でも、<b data-path-to-node="7" data-index-in-node="3">「例外の型（種類）」</b> を適切に使い分けるだけで、コードの品質がグッと上がり、バグの原因究明が驚くほど早くなるんです。</p>
<p data-path-to-node="8">今回は、PHPの標準例外（SPL）の中でも特に重要な <b data-path-to-node="8" data-index-in-node="27"><code data-path-to-node="8" data-index-in-node="27">LogicException</code></b>、<b data-path-to-node="8" data-index-in-node="42"><code data-path-to-node="8" data-index-in-node="42">DomainException</code></b>、<b data-path-to-node="8" data-index-in-node="58"><code data-path-to-node="8" data-index-in-node="58">RuntimeException</code></b> の3つについて、<b data-path-to-node="8" data-index-in-node="83">「現場ではどう使い分けているのか」</b> を解説していきます！</p>
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="2175" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">なぜ使い分ける必要があるの？</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-2">LogicException（ロジック例外）</a></li><li class="rtoc-item"><a href="#rtoc-3">2. DomainException（ドメイン例外）</a></li><li class="rtoc-item"><a href="#rtoc-4">3. RuntimeException（実行時例外）</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-5">まとめ</a></li></ol></div><h2 id="rtoc-1"  data-path-to-node="9">なぜ使い分ける必要があるの？</h2>
<p data-path-to-node="10">結論から言うと、<b data-path-to-node="10" data-index-in-node="8">「誰のせいなのか」</b> をはっきりさせるためです。</p>
<p data-path-to-node="11">エラーが起きたとき、それが「プログラマーのミス（バグ）」なのか、「運悪くサーバーが落ちた（環境要因）」のかによって、対応方法は変わりますよね？</p>
<ul data-path-to-node="12">
<li>
<p data-path-to-node="12,0,0"><b data-path-to-node="12,0,0" data-index-in-node="0">バグなら</b> → コードを修正しないといけない</p>
</li>
<li>
<p data-path-to-node="12,1,0"><b data-path-to-node="12,1,0" data-index-in-node="0">環境要因なら</b> → リトライしたり、ユーザーに「混み合ってます」と伝えたりする</p>
</li>
</ul>
<p data-path-to-node="13">これをクラスの型で表現するために、使い分けが必要なんです。</p>
<h3 id="rtoc-2"  data-path-to-node="15">LogicException（ロジック例外）</h3>
<p data-path-to-node="16"><b data-path-to-node="16" data-index-in-node="0">「これは開発者のミス！ コードを直して！」</b></p>
<p data-path-to-node="17">これは、「プログラムの論理がおかしい」ときに投げる例外です。 基本的に、<b data-path-to-node="17" data-index-in-node="36">本番環境でこれが出たらアウト</b>。即修正案件です。</p>
<p data-path-to-node="18">例えば、「APIキーをセットしていないのに、リクエストを送ろうとした」みたいなケースですね/p&gt;</p>
<pre class="line-numbers"><code class="language-php">
class ApiClient
{
    private ?string $apiKey = null;

    public function setApiKey(string $key): void
    {
        $this-&gt;apiKey = $key;
    }

    public function request(): void
    {
        if ($this-&gt;apiKey === null) {
            // 開発者がセットアップ手順を間違えているため、LogicException
            throw new \LogicException('API Keyが設定されていません。request()の前にsetApiKey()を呼んでください。');
        }

        // リクエスト処理...
    }
}
</code></pre>
<p>&nbsp;</p>
<p data-path-to-node="20">この例外が出たら、<code data-path-to-node="20" data-index-in-node="9">catch</code> して握りつぶすのではなく、コード自体を直しましょう。</p>
<h3 id="rtoc-3"  data-path-to-node="21">2. DomainException（ドメイン例外）</h3>
<p data-path-to-node="22"><b data-path-to-node="22" data-index-in-node="0">「そのデータ、仕様としてありえないよ！」</b></p>
<p data-path-to-node="23">これは <code data-path-to-node="23" data-index-in-node="4">LogicException</code> の親戚みたいなものです。 「ロジックは動くけど、渡されたデータがビジネスルール（仕様）としてありえない」場合に使います。</p>
<p data-path-to-node="24">例えば、「信号機の色」を扱うクラスがあったとして、「紫」を指定されたら困りますよね？</p>
<div _ngcontent-ng-c1297688001="" class="code-block ng-tns-c1297688001-182 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_3ddd59c9e0f35997&quot;,&quot;c_864d881f3293f3e8&quot;,null,&quot;rc_69e8998f44149c04&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c1297688001="" class="formatted-code-block-internal-container ng-tns-c1297688001-182">
<div _ngcontent-ng-c1297688001="" class="animated-opacity ng-tns-c1297688001-182">
<pre _ngcontent-ng-c1297688001="" class="ng-tns-c1297688001-182"><code _ngcontent-ng-c1297688001="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c1297688001-182"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TrafficLight</span>
</span>{
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">const</span> ALLOWED_COLORS = [<span class="hljs-string">'red'</span>, <span class="hljs-string">'yellow'</span>, <span class="hljs-string">'blue'</span>];

    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">__construct</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> <span class="hljs-variable">$color</span></span>)
    </span>{
        <span class="hljs-keyword">if</span> (!in_array(<span class="hljs-variable">$color</span>, <span class="hljs-built_in">self</span>::ALLOWED_COLORS, <span class="hljs-literal">true</span>)) {
            <span class="hljs-comment">// 定義外の値がコードから渡された！</span>
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">DomainException</span>(<span class="hljs-string">"色 '<span class="hljs-subst">{$color}</span>' は信号機に存在しません。"</span>);
        }
    }
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p data-path-to-node="26">ユーザーの入力ミスというよりは、「コード上で変な値を渡してしまった」ときに検知するためのものです。</p>
<h3 id="rtoc-4"  data-path-to-node="27">3. RuntimeException（実行時例外）</h3>
<p data-path-to-node="28"><b data-path-to-node="28" data-index-in-node="0">「コードは合ってるけど、環境のせいで失敗しました…」</b></p>
<p data-path-to-node="29">一番よく使うのがこれです。 コードは正しいけれど、<b data-path-to-node="29" data-index-in-node="25">「DBに繋がらない」「ファイルがない」「外部APIが落ちてる」</b> といった、実行時の状況（Runtime）によって起きるエラーです。</p>
<div _ngcontent-ng-c1297688001="" class="code-block ng-tns-c1297688001-183 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_3ddd59c9e0f35997&quot;,&quot;c_864d881f3293f3e8&quot;,null,&quot;rc_69e8998f44149c04&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c1297688001="" class="formatted-code-block-internal-container ng-tns-c1297688001-183">
<div _ngcontent-ng-c1297688001="" class="animated-opacity ng-tns-c1297688001-183">
<pre _ngcontent-ng-c1297688001="" class="ng-tns-c1297688001-183"><code _ngcontent-ng-c1297688001="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c1297688001-183"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ConfigLoader</span>
</span>{
    <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">load</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> <span class="hljs-variable">$filePath</span></span>): <span class="hljs-title">array</span>
    </span>{
        <span class="hljs-keyword">if</span> (!file_exists(<span class="hljs-variable">$filePath</span>)) {
            <span class="hljs-comment">// パスは合ってるはずだけど、ファイルが消えてる（実行時の事情）</span>
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> \<span class="hljs-built_in">RuntimeException</span>(<span class="hljs-string">"設定ファイルが見つかりません: <span class="hljs-subst">{$filePath}</span>"</span>);
        }
        
        <span class="hljs-comment">// 読み込み処理...</span>
    }
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p data-path-to-node="31">このエラーが出たときは、<code data-path-to-node="31" data-index-in-node="12">try-catch</code> で捕まえて「ただいま混み合っております」のようなエラー画面を出してあげる必要があります</p>
<h2 id="rtoc-5"  data-path-to-node="33">まとめ</h2>
<ul data-path-to-node="34">
<li>
<p data-path-to-node="34,0,0"><b data-path-to-node="34,0,0" data-index-in-node="0">Logic / Domain 系</b></p>
<ul data-path-to-node="34,0,1">
<li>
<p data-path-to-node="34,0,1,0,0">意味：「コードのバグ」</p>
</li>
<li>
<p data-path-to-node="34,0,1,1,0">対応：コードを修正する（Catchして無視しちゃダメ！）</p>
</li>
</ul>
</li>
<li>
<p data-path-to-node="34,1,0"><b data-path-to-node="34,1,0" data-index-in-node="0">Runtime 系</b></p>
<ul data-path-to-node="34,1,1">
<li>
<p data-path-to-node="34,1,1,0,0">意味：「実行時のトラブル」</p>
</li>
<li>
<p data-path-to-node="34,1,1,1,0">対応：エラー画面を出したり、ログに残したりして運用でカバーする</p>
</li>
</ul>
</li>
</ul>
<p data-path-to-node="35">この意識を持つだけで、「エラーが起きたときに何をすればいいか」が一瞬でわかるようになります。 ぜひ、明日からのコーディングで意識してみてくださいね！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/2175/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Laravel+Inertia+ReactをECSで動かしたい！ NginxとPHP-FPMのコンテナ分離</title>
		<link>https://otonan-syusyoku.work/archives/2153</link>
					<comments>https://otonan-syusyoku.work/archives/2153#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Tue, 28 Oct 2025 05:24:52 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[インフラ]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[LAMP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[ネットワーク]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=2153</guid>

					<description><![CDATA[Laravel + Inertia (React/Vue) の組み合わせは、SPA（シングルページアプリケーション）の体験とサーバーサイド（Laravel）の書きやすさを両立できる、非常に強力な構成です。 しかし、ローカ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Laravel + Inertia (React/Vue) の組み合わせは、SPA（シングルページアプリケーション）の体験とサーバーサイド（Laravel）の書きやすさを両立できる、非常に強力な構成です。</p>
<p>しかし、ローカルのDocker Compose環境では問題なく動作しても、AWSのECS Fargateのような本番環境にデプロイしようとすると、いくつかの疑問に直面します。</p>
<ul>
<li>「NginxとPHP-FPMコンテナはどう連携させるのがベスト？」</li>
<li>「<code>fastcgi_pass</code> ってローカルと設定を変える必要ある？」</li>
<li>「InertiaでビルドしたReactのJS/CSSファイルは、結局どのコンテナに置くのが正解？」</li>
</ul>
<p>この記事では、<code>fastcgi_pass</code> の基本から、ECS Fargateでの最適なコンテナ構成、そしてInertia/Reactプロジェクト特有の「静的ファイルの配置場所」問題までを、順を追って解説します。</p>
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="2153" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">fastcgi_pass とは？</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-2">NginxとPHP-FPMの「橋渡し」</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-3">ローカル開発 (Docker Compose) での構成</a></li><li class="rtoc-item"><a href="#rtoc-4">【1タスク2コンテナ】本番 (ECS Fargate) での構成：</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-5">ECS Fargateでのfastcgi_passはどうなる？</a></li><li class="rtoc-item"><a href="#rtoc-6">タスク定義のイメージ</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-7">Inertia/Reactのビルドファイルはどこに置く？</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-8">ステップ1: HTMLシェルのリクエスト (PHP-FPMが処理)</a></li><li class="rtoc-item"><a href="#rtoc-9">ステップ2: 静的アセット(JS/CSS)のリクエスト (Nginxが処理)</a></li><li class="rtoc-item"><a href="#rtoc-10">CI/CDでのベストプラクティス</a></li><li class="rtoc-item"><a href="#rtoc-11"><b>結論</b></a></li></ul></li><li class="rtoc-item"><a href="#rtoc-12">まとめ</a></li></ol></div><h2 id="rtoc-1" >fastcgi_pass とは？</h2>
<h3 id="rtoc-2" >NginxとPHP-FPMの「橋渡し」</h3>
<p>まず基本のおさらいです。Nginxは高性能なWebサーバーですが、それ自体はPHPコードを実行できません。<br />
一方、PHP-FPMはPHPコードを実行することに特化したプロセス（サーバー）です。</p>
<p>Nginxがクライアント（ブラウザ）から <code>.php</code> ファイルへのリクエストを受け取ったとき、そのリクエストをPHP-FPMに処理してもらう必要があります。</p>
<p>このとき、Nginxの設定ファイル（<code>nginx.conf</code>）で、<b>「どのPHP-FPMに処理を依頼するか」の宛先を指定する</b>のが <code>fastcgi_pass</code> ディレクティブです。</p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-470 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-470">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-470">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-470"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-470"><span class="hljs-attribute">location</span> <span class="hljs-regexp">~ \.php$</span> {
    <span class="hljs-comment"># ...</span>
    <span class="hljs-comment"># ↓ この一行が「橋渡し」の指定</span>
    <span class="hljs-attribute">fastcgi_pass</span> php-fpm-server:<span class="hljs-number">9000</span>; 
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<h2 id="rtoc-3" >ローカル開発 (Docker Compose) での構成</h2>
<p>ローカル開発では、「1コンテナ1責務」の原則に従い、NginxとPHP-FPMを別々のコンテナとして <code>docker-compose.yml</code> で定義するのが一般的です。</p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-471 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-471">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-471">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-471"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-471"><span class="hljs-comment"># docker-compose.yml (抜粋)</span>
<span class="hljs-attr">version:</span> <span class="hljs-string">'3'</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-comment"># Nginxコンテナ</span>
  <span class="hljs-attr">nginx:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:alpine</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"80:80"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx.conf:/etc/nginx/conf.d/default.conf</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./laravel-project:/var/www/html</span>

  <span class="hljs-comment"># PHP-FPMコンテナ</span>
  <span class="hljs-attr">php:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span> <span class="hljs-comment"># PHP-FPMとLaravelコードを含むDockerfile</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./laravel-project:/var/www/html</span>
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>この構成では、NginxコンテナとPHPコンテナは <b>別々のネットワーク空間</b> に存在します。Docker Composeが提供する内部ネットワークを介して、サービス名で通信します。</p>
<p>したがって、NginxコンテナからPHPコンテナへは、<code>php</code> というサービス名（ホスト名）を使ってアクセスします。</p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-472 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-472">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-472">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-472"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-472"><span class="hljs-comment"># nginx.conf (Docker Compose用)</span>
<span class="hljs-attribute">location</span> <span class="hljs-regexp">~ \.php$</span> {
    <span class="hljs-comment"># ...</span>
    <span class="hljs-comment"># 'php' サービス（コンテナ）の 9000番ポートに転送</span>
    <span class="hljs-attribute">fastcgi_pass</span> php:<span class="hljs-number">9000</span>;
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>（※ このTCP/IP通信によるパフォーマンスやセキュリティの懸念は、コンテナ間通信がDockerの内部ネットワークに限定されていれば、実用上ほとんど問題になりません。）</p>
<h2 id="rtoc-4" >【1タスク2コンテナ】本番 (ECS Fargate) での構成：</h2>
<p>さて、本題のECS Fargateです。<br />
ECSでは、<code>docker-compose.yml</code> に相当するものとして「タスク定義 (Task Definition)」を使います。</p>
<p>ここで重要なキーポイントは、<strong>「1つのタスク定義の中で、NginxコンテナとPHP-FPMコンテナの2つを定義する」</strong>ことです。</p>
<p><strong>これら2つのコンテナは、1セットで「Webアプリケーションサーバー」</strong>として機能します。</p>
<h3 id="rtoc-5" >ECS Fargateでのfastcgi_passはどうなる？</h3>
<p>ECSの同一タスク内で実行されるコンテナは、<b>同じネットワーク空間（ネットワークモード <code>awsvpc</code>）を共有します</b>。</p>
<p>これは、Nginxコンテナから見ると、PHP-FPMコンテナが「他人」ではなく、「自分自身（localhost）」として見えることを意味します。</p>
<p>したがって、ECS Fargate用のNginxイメージに含める <code>nginx.conf</code> の設定は、以下のようになります。</p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-473 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-473">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-473">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-473"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-473"><span class="hljs-comment"># nginx.conf (ECS Fargate用)</span>
<span class="hljs-attribute">location</span> <span class="hljs-regexp">~ \.php$</span> {
    <span class="hljs-comment"># ...</span>
    <span class="hljs-comment"># サービス名ではなく、localhost (127.0.0.1) を指定する</span>
    <span class="hljs-attribute">fastcgi_pass</span> <span class="hljs-number">127.0.0.1:9000</span>;
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<h3 id="rtoc-6" >タスク定義のイメージ</h3>
<p>タスク定義では、以下のように設定します。</p>
<ul>
<li><b>コンテナ-A: <code>php-fpm-container</code></b>
<ul>
<li>イメージ: （Laravelコードを含むPHP-FPMイメージ）</li>
<li>ポートマッピング: <b>なし</b> (外部に公開する必要はないため)</li>
</ul>
</li>
<li><b>コンテナ-B: <code>nginx-container</code></b>
<ul>
<li>イメージ: （設定済みのnginx.confと静的ファイルを含むNginxイメージ）</li>
<li>ポートマッピング: <b><code>80:80</code></b> (ALBからのトラフィックを受け取るため)</li>
</ul>
</li>
</ul>
<p>ALB（ロードバランサー）からのトラフィックはNginxコンテナが受け取り、必要に応じて <code>localhost:9000</code> を介してPHP-FPMコンテナに処理を渡します。</p>
<h2 id="rtoc-7" >Inertia/Reactのビルドファイルはどこに置く？</h2>
<p>ここで、Inertia/React構成特有の問題に直面します。</p>
<p>「InertiaはLaravel（PHP）がビューを配信する仕組みだから、<code>npm run build</code> で生成された <code>public/build</code> フォルダは、PHP-FPMコンテナにだけ置けば良いのでは？」</p>
<p>これはよくある誤解ですが、<b>パフォーマンスと責務分離の観点から、ビルドした静的ファイル（JS/CSS）はNginxコンテナに配置するのが正解</b>です。</p>
<p>この理由を理解するために、Inertiaのページが読み込まれる2段階のフローを見てみましょう。</p>
<h3 id="rtoc-8" >ステップ1: HTMLシェルのリクエスト (PHP-FPMが処理)</h3>
<ol start="1">
<li>ブラウザが <code>https://example.com/dashboard</code> にアクセスします。</li>
<li>ALB → Nginxコンテナがリクエストを受け取ります。</li>
<li>NginxはこれがPHPのリクエストだと判断し、<code>fastcgi_pass 127.0.0.1:9000</code> を使って<b>PHP-FPMコンテナ</b>に転送します。</li>
<li>PHP (Laravel) が起動し、Inertiaは <code>app.blade.php</code> をレンダリングしようとします。</li>
<li>このとき、PHPは <b><code>public/build/manifest.json</code></b> を読み取り、HTMLに含めるべきJS/CSSのファイル名を特定します。</li>
<li>PHPは以下のようなHTMLの「ガワ」を<b>生成</b>し、Nginx経由でブラウザに返します。
<p><response-element class="" ng-version="0.0.0-PLACEHOLDER"><code-block _nghost-ng-c535465467="" class="ng-tns-c535465467-474 ng-star-inserted"></p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-474 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-474">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-474">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-474"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-474"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/build/assets/app.12345.js"</span> <span class="hljs-attr">defer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/build/assets/app.67890.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span> <span class="hljs-attr">data-page</span>=<span class="hljs-string">"..."</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
</div>
</div>
</div>
<p></code-block></response-element></li>
</ol>
<h3 id="rtoc-9" >ステップ2: 静的アセット(JS/CSS)のリクエスト (Nginxが処理)</h3>
<ol start="1">
<li>ブラウザは、ステップ1で受け取ったHTMLを解析します。</li>
<li>「<code>/build/assets/app.12345.js</code> と <code>/build/assets/app.67890.css</code> が必要だ」と判断し、ブラウザは<b>別途2回のリクエスト</b>をサーバーに送信します。</li>
<li><b>このリクエストは、もはやPHPとは全く関係ありません。</b></li>
<li>ALB → <b>Nginxコンテナ</b>がこの2つのリクエストを受け取ります。</li>
<li>Nginxは「自分の管理下（<code>public</code> フォルダ）にそのファイルがあるか？」を探します。</li>
<li><b>Nginxコンテナに <code>public/build/</code> 以下の実体ファイルが存在するため</b>、NginxはPHP-FPMを起動することなく、それらの静的ファイルを<b>超高速で</b>ブラウザに直接返します。</li>
</ol>
<p>もし、NginxコンテナにJS/CSSファイルがなければ、このリクエストもPHP-FPMに転送されてしまい、「JSファイルを取得するためだけにLaravelを起動する」という深刻なパフォーマンスボトルネックが発生します。</p>
<h3 id="rtoc-10" >CI/CDでのベストプラクティス</h3>
<p>上記2ステップから、CI/CDパイプラインでDockerイメージをビルドする際は、以下の構成が最適です。</p>
<ol start="1">
<li><code>npm run build</code> を実行し、<code>public/build</code> ディレクトリを生成します。</li>
<li><b>PHP-FPMイメージのビルド:</b>
<ul>
<li>Laravelのコード（<code>app/</code>, <code>routes/</code> など）をコピーします。</li>
<li>ステップ1のために <b><code>public/build/manifest.json</code></b> をコピーします。（リンク生成に必要）</li>
</ul>
</li>
<li><b>Nginxイメージのビルド:</b>
<ul>
<li><code>nginx.conf</code> をコピーします。</li>
<li>ステップ2のために <b><code>public</code> フォルダ全体</b>（<code>index.php</code> と、<code>public/build</code> 以下の <b>全てのJS/CSSファイル</b> を含む）をコピーします。（静的アセットの配信用）</li>
</ul>
</li>
</ol>
<h3 id="rtoc-11" ><b>結論</b></h3>
<p><code>manifest.json</code> はPHP-FPMコンテナに、JS/CSSの実体ファイルはNginxコンテナに必要です。</p>
<p>両方のイメージに <code>public</code> フォルダ（または <code>public/build</code>）全体をコピーするのが、最もシンプルで確実な方法です。</p>
<h2 id="rtoc-12" >まとめ</h2>
<p>ECS Fargateで Laravel + Inertia + React 構成を動かすための要点をまとめます。</p>
<ol start="1">
<li><b>構成</b>: 「1タスク2コンテナ（Nginx + PHP-FPM）」構成を採用します。</li>
<li><b><code>fastcgi_pass</code></b>: NginxからPHP-FPMへの通信は、同一タスク内のため <code>fastcgi_pass 127.0.0.1:9000;</code> を指定します。</li>
<li><b>静的ファイル</b>: ビルドしたJS/CSSは、パフォーマンス最適化のためNginxコンテナに配置し、Nginxから直接配信させます。</li>
<li><b><code>manifest.json</code></b>: HTMLシェル生成のため、PHP-FPMコンテナにも <code>manifest.json</code> が必要です。</li>
</ol>
<p>この構成により、PHP-FPMは動的処理に専念し、Nginxは静的ファイルの高速配信に専念するという、「1コンテナ1責務」のメリットを最大限に活かした、スケーラブルな本番環境を構築できます。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/2153/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【今日の覚書】static メソッドは適切に</title>
		<link>https://otonan-syusyoku.work/archives/1817</link>
					<comments>https://otonan-syusyoku.work/archives/1817#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Thu, 12 Sep 2024 07:50:30 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[生涯独学]]></category>
		<category><![CDATA[LAMP]]></category>
		<category><![CDATA[コーディング]]></category>
		<category><![CDATA[脱3流プログラマー]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1817</guid>

					<description><![CDATA[static おじさんになりかけたので、備忘録として学習の記録を残します。 I`m PHPer!!!!! Contents 便利なstatic使うべきタイミング状態を持たない処理ファクトリーメソッドシングルトンパターンだ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>static おじさんになりかけたので、備忘録として学習の記録を残します。</p>
<p>I`m PHPer!!!!!</p>
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="1817" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">便利なstatic</a></li><li class="rtoc-item"><a href="#rtoc-2">使うべきタイミング</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-3">状態を持たない処理</a></li><li class="rtoc-item"><a href="#rtoc-4">ファクトリーメソッド</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-5">シングルトンパターン</a></li><li class="rtoc-item"><a href="#rtoc-6">だめな使い方</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-7">インスタンスの状態を操作する処理</a></li><li class="rtoc-item"><a href="#rtoc-8">過度な使用</a></li><li class="rtoc-item"><a href="#rtoc-9">依存性注入の回避</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-10">まとめ</a></li></ol></div><h2 id="rtoc-1" >便利なstatic</h2>
<p>PHPの <strong>static メソッド</strong>は、インスタンスを生成せずにクラスから直接呼び出せるメソッドです。</p>
<h2 id="rtoc-2" >使うべきタイミング</h2>
<p><a href="https://otonan-syusyoku.work/archives/1095/php" rel="attachment wp-att-1098"><img fetchpriority="high" decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2022/03/PHP.png" alt="PHP" width="1000" height="500" class="aligncenter size-full wp-image-1098" srcset="https://otonan-syusyoku.work/wp-content/uploads/2022/03/PHP.png 1000w, https://otonan-syusyoku.work/wp-content/uploads/2022/03/PHP-300x150.png 300w, https://otonan-syusyoku.work/wp-content/uploads/2022/03/PHP-768x384.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></a></p>
<h3 id="rtoc-3" >状態を持たない処理</h3>
<p>インスタンスの状態に依存しない、独立した処理を行う場合に適しています。例えば、ユーティリティ関数やヘルパー関数などがこれに該当します。</p>
<pre class="line-numbers"><code class="language-php">class MathHelper {
  public static function add($a, $b) {
    return $a + $b;
  }
}

echo MathHelper::add(3, 4); // 出力: 7
</code></pre>
<p>&nbsp;</p>
<h3 id="rtoc-4" >ファクトリーメソッド</h3>
<p>クラスのインスタンスを生成するメソッド（ファクトリーメソッド）として使用されることがあります。</p>
<p>この場合、<strong>`new`キーワード</strong>を隠蔽して、インスタンス化の過程を制御できます。</p>
<pre class="line-numbers"><code class="language-php">class User {
  public $name;

  private function __construct($name) {
    $this-&gt;name = $name;
  }

  public static function create($name) {
    return new self($name);
  }
}

$user = User::create('John Doe');
</code></pre>
<p>&nbsp;</p>
<p>あまり使いたくないね。。。</p>
<p>&nbsp;</p>
<h2 id="rtoc-5" >シングルトンパターン</h2>
<p>特定のクラスのインスタンスが一つだけ存在することを保証するシングルトンパターンの実装に利用されます。</p>
<pre class="line-numbers"><code class="language-php">&lt;?php

class Singleton
{
    private static $instance;

    private function __construct()
    {
// プライベートコンストラクタ
    }

    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
}

$singleton = Singleton::getInstance();
</code></pre>
<p>&nbsp;</p>
<h2 id="rtoc-6" >だめな使い方</h2>
<h3 id="rtoc-7" >インスタンスの状態を操作する処理</h3>
<p>インスタンスの状態に依存するメソッドに`static`を使うべきではありません。<code>static</code>メソッドはクラスレベルで動作するため、インスタンス固有の状態を保持することができません。</p>
<pre class="line-numbers"><code class="language-php">class User {
  private $name;

  public static function setName($name) {
    $this-&gt;name = $name; // エラー: $thisを使えない
  }
}
</code></pre>
<p>&nbsp;</p>
<h3 id="rtoc-8" >過度な使用</h3>
<p>全てのメソッドを`static`にすることは避けるべきです。</p>
<p><code>static</code>メソッドを多用すると、オブジェクト指向プログラミングの基本原則である<code>カプセル化</code>や<code>多態性</code>が損なわれる可能性があります。<br />
特に、後からメソッドをオーバーライドする必要が出てきた場合に柔軟性を失います。</p>
<h3 id="rtoc-9" >依存性注入の回避</h3>
<p><code>static</code>メソッドは依存性注入と相性が悪く、テストやメンテナンスが難しくなる場合があります。テスト可能なコードを維持するためには、インスタンスメソッドを使用し、必要な依存関係をコンストラクタやセッターで注入する方が望ましいです。</p>
<h2 id="rtoc-10" >まとめ</h2>
<p><code>static</code> メソッドは、クラス固有の処理やユーティリティ関数として適切に使用することで、コードの構造を明確にし、インスタンス化を不要にするメリットがあります。ただし、過度な使用はオブジェクト指向の原則を損なう可能性があるため、状況に応じて適切に使い分けることが重要です。</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1817/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Laravelプロジェクト】DeployerでのデプロイでBuildエラー</title>
		<link>https://otonan-syusyoku.work/archives/1819</link>
					<comments>https://otonan-syusyoku.work/archives/1819#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Tue, 13 Aug 2024 21:40:34 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1819</guid>

					<description><![CDATA[Contents 概要エラー内容環境原因解決方法rollupのインストールdeployerのBuildタスクの修正番外編おわり概要 Deployerを使ってクラウドサーバーへのデプロイを行うとBuildエラーが発生した。 [&#8230;]]]></description>
										<content:encoded><![CDATA[<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="1819" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">概要</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-2">エラー内容</a></li><li class="rtoc-item"><a href="#rtoc-3">環境</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-4">原因</a></li><li class="rtoc-item"><a href="#rtoc-5">解決方法</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-6">rollupのインストール</a></li><li class="rtoc-item"><a href="#rtoc-7">deployerのBuildタスクの修正</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-8">番外編</a></li><li class="rtoc-item"><a href="#rtoc-9">おわり</a></li></ol></div><h2 id="rtoc-1" >概要</h2>
<p>Deployerを使ってクラウドサーバーへのデプロイを行うとBuildエラーが発生した。</p>
<p>ローカルでのビルドは問題なく通るのですが、クラウドサーバーへ上げる際に死ぬ。</p>
<p>初めて出会ったエラーのため解消に時間がかかったので、助かる人が増えることを願って記事に残します。</p>
<h3 id="rtoc-2" >エラー内容</h3>
<pre class="line-numbers"><code class="language-other">npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/@rollup%2frollup-linux-x64-musl--save-optional - Not found
npm ERR! 404 
npm ERR! 404  '@rollup/rollup-linux-x64-musl--save-optional@*' is not in this registry.
npm ERR! 404 
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.

npm ERR! A complete log of this run can be found in: /Users/oshidamarina/.npm/_logs/2024-08-13T03_48_16_120Z-debug-0.log</code></pre>
<h3 id="rtoc-3" >環境</h3>
<ul>
<li>Laravel 10</li>
<li>Vue3</li>
<li>TypeScript5</li>
<li>Tailwind</li>
<li>DaisyUi</li>
<li>Macbook Air（開発機）</li>
<li>AmazonLinux2023（本番サーバー）</li>
</ul>
<p><a href="https://otonan-syusyoku.work/archives/1674/lets-go" rel="attachment wp-att-1680"><img decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO.png" alt="Let&#96;s GO" width="1000" height="500" class="aligncenter size-full wp-image-1680" srcset="https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO.png 1000w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO-300x150.png 300w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO-768x384.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></a></p>
<h2 id="rtoc-4" >原因</h2>
<p>Viteのビルド中に発生する `<code>@rollup/rollup-linux-x64-musl</code>` モジュールが見つからない問題に対処しています。この問題は、ViteがRollupのネイティブバイナリに依存しているため、特定の環境（特にDockerコンテナやLinux環境）で発生することがあるとのこと。</p>
<p><a href="https://github.com/vitejs/vite/discussions/15532">https://github.com/vitejs/vite/discussions/15532</a></p>
<h2 id="rtoc-5" >解決方法</h2>
<h3 id="rtoc-6" >rollupのインストール</h3>
<pre class="line-numbers"><code class="language-other">npm install @rollup/rollup-linux-x64-musl --save-optional
</code></pre>
<p>package.json に下記の記載があること。</p>
<pre class="line-numbers"><code class="language-php">"optionalDependencies": {
      "@rollup/rollup-linux-x64-musl": "^4.20.0"
 }</code></pre>
<h3 id="rtoc-7" >deployerのBuildタスクの修正</h3>
<pre class="line-numbers"><code class="language-php">task('deploy', [
    'deploy:prepare',
    'deploy:vendors',
    'deploy:shared',
    'deploy:writable',
    'build',
    'artisan:migrate',
    'deploy:publish',
]);

// Build task: run npm install and npm run build
desc('Build the project');
task('build', function () {
    run('cd {{release_path}} &amp;&amp; npm install &amp;&amp; npm run build');
});</code></pre>
<p>&nbsp;</p>
<h2 id="rtoc-8" >番外編</h2>
<p>DeployerのBuildタスクを以下のように調整してみると僕の環境では通りました。</p>
<pre class="line-numbers"><code class="language-php">task('deploy', [
    'deploy:prepare',
    'deploy:vendors',
    'deploy:shared',
    'deploy:writable',
    'build',
    'artisan:migrate',
    'deploy:publish', 
]);

// Build task: run npm install and npm run build
desc('Build the project');
task('build', function () {
    run('cd {{release_path}} &amp;&amp; rm -rf node_modules package-lock.json'); // FIXME： 原因は他にある
    run('cd {{release_path}} &amp;&amp; npm install &amp;&amp; npm run build');
});</code></pre>
<p>ただし、この方法ではBuildは成功するが、ブラウザ表示に難がでてくるという記事もあったため、取りやめ。</p>
<p>多くの人が解決しているであろう rollup の修正で対応することにしましたー。</p>
<h2 id="rtoc-9" >おわり</h2>
<p>Buildが通ったー！ってことで終わりです。<br />
Viteのバージョンを調整したりしたら意外とすんなり解決したりするのかなーとおもったり…</p>
<p>お困りの方も試してみてください。</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1819/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【PHP】僕がInterfaceを使う理由</title>
		<link>https://otonan-syusyoku.work/archives/1801</link>
					<comments>https://otonan-syusyoku.work/archives/1801#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sat, 27 Jul 2024 01:51:31 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[生涯独学]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[コーディング]]></category>
		<category><![CDATA[三流プログラマー]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1801</guid>

					<description><![CDATA[PHPでの開発を進める中で、Interfaceを使うことが多くなりました。 Interfaceは、コードの可読性や保守性を向上させる強力なツールです。 この記事では、僕がInterfaceを使う理由とその利点について、具 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>PHPでの開発を進める中で、Interfaceを使うことが多くなりました。</p>
<p>Interfaceは、コードの可読性や保守性を向上させる強力なツールです。</p>
<p>この記事では、僕がInterfaceを使う理由とその利点について、具体例を交えながら説明します。</p>
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="1801" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">コードの一貫性を保つ</a></li><li class="rtoc-item"><a href="#rtoc-2">依存関係の注入を容易にする</a></li><li class="rtoc-item"><a href="#rtoc-3">テストの容易化</a></li><li class="rtoc-item"><a href="#rtoc-4">拡張性の向上</a></li><li class="rtoc-item"><a href="#rtoc-5">まとめ</a></li></ol></div><h2 id="rtoc-1" >コードの一貫性を保つ</h2>
<p>Interfaceを使うことで、プロジェクト全体で一貫したメソッドシグネチャを保つことができます。例えば、複数のクラスが同じ操作を実行する場合、それぞれのクラスに同じメソッドを実装させることが可能です。これにより、コードを読む際にメソッドの名前や引数の形式に迷うことがなくなります。</p>
<pre class="line-numbers"><code class="language-php">interface LoggerInterface {
  public function log(string $message): void;
}

class FileLogger implements LoggerInterface {
  public function log(string $message): void {
    // ファイルにログを記録する処理
  }
}

class DatabaseLogger implements LoggerInterface {
  public function log(string $message): void {
    // データベースにログを記録する処理
  }
}
</code></pre>
<p>&nbsp;</p>
<h2 id="rtoc-2" >依存関係の注入を容易にする</h2>
<p>Interfaceを使うことで、依存関係の注入が容易になります。</p>
<p>特定のクラスに依存するのではなく、Interfaceに依存することで、将来的にクラスを変更する場合でも、コード全体に大きな影響を与えずに済みます。</p>
<pre class="line-numbers"><code class="language-php">class UserController {
  private $logger;

  public function __construct(LoggerInterface $logger) {
    $this-&gt;logger = $logger;
  }

  public function createUser(string $name): void {
    // ユーザー作成の処理
    $this-&gt;logger-&gt;log("User created: $name");
  }
}
</code></pre>
<p>&nbsp;</p>
<h2 id="rtoc-3" >テストの容易化</h2>
<p>Interfaceを使用することで、テストが容易になります。<br />
モックオブジェクトやスタブを使って、依存関係を簡単に置き換えることができるため、ユニットテストの実行が簡単になります。</p>
<p>モックができないとUTが書きづらい場面が多々出てくるので、そのためだけに Interface を使っていると言っても過言ではないです。</p>
<pre class="line-numbers"><code class="language-php">class MockLogger implements LoggerInterface {
  public function log(string $message): void {
    // テスト用のモック処理
  }
}

$logger = new MockLogger();
$controller = new UserController($logger);
$controller-&gt;createUser('John Doe');
// ここでログが正しく動作するかをテスト
</code></pre>
<p>&nbsp;</p>
<h2 id="rtoc-4" >拡張性の向上</h2>
<p>Interfaceを使うことで、新しい機能の追加が容易になります。</p>
<p>例えば、新しいタイプのLoggerを追加する場合、既存のコードを変更することなく、新しいクラスを追加するだけで済みます。</p>
<pre class="line-numbers"><code class="language-php">class EmailLogger implements LoggerInterface {
  public function log(string $message): void {
    // メールにログを送信する処理
  }
}
</code></pre>
<p>&nbsp;</p>
<h2 id="rtoc-5" >まとめ</h2>
<p>Interfaceを使うことで、コードの一貫性、依存関係の管理、テストの容易化、拡張性の向上といった多くの利点があります。PHPでの開発において、Interfaceを効果的に活用することで、より健全で保守性の高いコードを実現することができます。ぜひ、皆さんもInterfaceの利点を活用してみてください。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1801/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>意外と見落とされがち！PHP.iniの重要な設定ポイント</title>
		<link>https://otonan-syusyoku.work/archives/1753</link>
					<comments>https://otonan-syusyoku.work/archives/1753#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sun, 12 May 2024 06:13:53 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tips]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1753</guid>

					<description><![CDATA[PHPを扱う際、多くの開発者がphp.iniの設定を最適化することの重要性を見落としがちです。このファイルはPHPの動作をカスタマイズし、セキュリティを強化するためのキーとなります。今回の記事では、意外とできていないph [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>PHPを扱う際、多くの開発者がphp.iniの設定を最適化することの重要性を見落としがちです。このファイルはPHPの動作をカスタマイズし、セキュリティを強化するためのキーとなります。今回の記事では、意外とできていないphp.iniの設定に焦点を当て、その設定方法とそれぞれの設定がもたらす影響について解説します。</p>
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="1753" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">メモリ制限の設定 (memori_limit)</a></li><li class="rtoc-item"><a href="#rtoc-2">実行時間の制限 (max_execution_time)</a></li><li class="rtoc-item"><a href="#rtoc-3">エラーレポーティング (error_reporting)</a></li><li class="rtoc-item"><a href="#rtoc-4">ファイルアップロード (file_uploads)</a></li><li class="rtoc-item"><a href="#rtoc-5">セッションのセキュリティ設定</a></li><li class="rtoc-item"><a href="#rtoc-6">まとめ</a></li></ol></div><h2 id="rtoc-1" >メモリ制限の設定 (memori_limit)</h2>
<p>PHPスクリプトが消費することができる最大メモリ量を指定します。デフォルト設定では「128M」が多いですが、大規模なアプリケーションを扱う場合はこの値を増やす必要があります。不足するとスクリプトが突然停止することがあるため、適切なメモリ量を設定しましょう。<span class="" data-state="closed"></span></p>
<pre class="line-numbers"><code class="!whitespace-pre hljs language-ini"><span class="hljs-attr">memory_limit</span> = <span class="hljs-number">256</span>M</code></pre>
<h2 id="rtoc-2" >実行時間の制限 (max_execution_time)</h2>
<p>スクリプトが実行を終了するまでの最大時間を秒単位で設定します。デフォルトは「30秒」ですが、時間がかかるプロセスを扱う場合はこの値を調整するこことが重要です。</p>
<pre class="line-numbers"><code class="language-php">max_execution_time = 60</code></pre>
<h2 id="rtoc-3" >エラーレポーティング (error_reporting)</h2>
<p>開発中はすべてのエラーを表示することが重要です。しかし、本番環境ではエラー表示を抑えるべきです。この設定を通じて、どのレベルのエラーをレポートするかを制御できます。</p>
<pre class="line-numbers"><code class="language-php">error_reporting = E_ALL &amp; ~E_DEPRECATED &amp; ~E_STRICT</code></pre>
<h2 id="rtoc-4" >ファイルアップロード (file_uploads)</h2>
<p>ファイルアップロードを許可するかどうかを制御します。セキュリティ上の理由から、使用しない場合は無効化することが推奨されます。</p>
<pre class="line-numbers"><code class="language-php">file_uploads = On</code></pre>
<h2 id="rtoc-5" >セッションのセキュリティ設定</h2>
<p>セッションIDの扱いには特に注意が必要です。セッションハイジャックを防ぐために、セッションIDの再生成やセキュアなクッキーの使用が推奨されます。</p>
<pre class="line-numbers">session.use_strict_mode = 1
session.cookie_secure = 1
session.cookie_httponly = 1</pre>
<h2 id="rtoc-6" >まとめ</h2>
<p>これらの設定は、PHPのパフォーマンスとセキュリティを大きく向上させることができます。php.iniの設定は一見複雑に見えるかもしれませんが、それぞれの項目に慎重に注意を払い、アプリケーションのニーズに応じて適切に調整することが非常に重要です。この記事があなたのPHP設定を見直すきっかけになれば幸いです。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1753/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CakePHPのmatchingで困った話</title>
		<link>https://otonan-syusyoku.work/archives/1729</link>
					<comments>https://otonan-syusyoku.work/archives/1729#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sat, 20 Apr 2024 11:49:20 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[古の技術]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1729</guid>

					<description><![CDATA[古の技術と呼ばれることも多くなってきたCakePHPの記事です。 CakePHPを使った開発の際に躓いたポイントを解説しますぅ Contents 概要関連データの取得方法MatchingとInnerJoinWith概要  [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>古の技術と呼ばれることも多くなってきたCakePHPの記事です。</p>
<p>CakePHPを使った開発の際に躓いたポイントを解説しますぅ</p>
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="1729" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">概要</a></li><li class="rtoc-item"><a href="#rtoc-2">関連データの取得方法</a></li><li class="rtoc-item"><a href="#rtoc-3">MatchingとInnerJoinWith</a></li></ol></div><h2 id="rtoc-1" >概要</h2>
<p>データ取得時に関連データを合わせて取得したい。関連データの取得時には条件に一致しないデータが</p>
<p>関連データを用いて取得条件を絞りこみ、関連データが条件に一致しない場合、親も取得しないようにしたい。</p>
<h2 id="rtoc-2" >関連データの取得方法</h2>
<p><span>CakePHPでのデータ取得は<code>matching</code>, <code>innerJoinWith</code> を用いることで、SQLのJOINに類似した操作が実現できます。</span></p>
<p><span>これにより、特定の関連データに基づく厳密なデータフィルタリングが可能となります。</span></p>
<p>matchingはN:Nの関係性のときに強力な関数となるが、条件指定の際に思った挙動にならないため注意が必要。</p>
<h2 id="rtoc-3" >MatchingとInnerJoinWith</h2>
<p>対応表として以下の形になる。</p>
<table style="border-collapse: collapse; width: 100%;">
<tbody>
<tr>
<td style="width: 33.4449%;"></td>
<td style="width: 33.2217%;">matching</td>
<td style="width: 33.3333%;">innerJoinWith</td>
</tr>
<tr>
<td style="width: 33.4449%;">関連データの取得</td>
<td style="width: 33.2217%;">できる</td>
<td style="width: 33.3333%;">できない</td>
</tr>
<tr>
<td style="width: 33.4449%;">関連データの条件指定</td>
<td style="width: 33.2217%;">できる</td>
<td style="width: 33.3333%;">できる</td>
</tr>
<tr>
<td style="width: 33.4449%;">条件一致しない場合の挙動</td>
<td style="width: 33.2217%;">空として</td>
<td style="width: 33.3333%;"></td>
</tr>
<tr>
<td style="width: 33.4449%;">生成されるSQL</td>
<td style="width: 33.2217%;"><span>Inner Join</span></td>
<td style="width: 33.3333%;"><span>Inner Join</span></td>
</tr>
<tr>
<td style="width: 33.4449%;">使用どころ</td>
<td style="width: 33.2217%;">N:Nの関係のときにとりあえず便利</td>
<td style="width: 33.3333%;"><span>関連データに基いて結果を計算したいとき使う<br />
(サブクエリとして取ったり…</span></td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1729/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CakePHPのURL生成で死んだ話</title>
		<link>https://otonan-syusyoku.work/archives/1731</link>
					<comments>https://otonan-syusyoku.work/archives/1731#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sat, 20 Apr 2024 10:07:10 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[生涯独学]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[古の技術]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1731</guid>

					<description><![CDATA[古の技術と呼ばれることも多くなってきたCakePHPの記事です。 CakePHPのマニュアルのせいで時間取られたので、備忘録として残しておきっます。 Contents 概要困ったこと概要 Commandクラスからメールに [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>古の技術と呼ばれることも多くなってきたCakePHPの記事です。</p>
<p>CakePHPのマニュアルのせいで時間取られたので、備忘録として残しておきっます。</p>
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="1731" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">概要</a></li><li class="rtoc-item"><a href="#rtoc-2">困ったこと</a></li></ol></div><h2 id="rtoc-1" >概要</h2>
<p>Commandクラスからメールに添付するURL生成を行いたい。</p>
<p>その際に生成されるURLはHTTPS化されたURLを添付したい。</p>
<p>&nbsp;</p>
<p>現環境 ↓</p>
<ul>
<li>CakePHP 4.4</li>
<li>PHP 8.1</li>
</ul>
<h2 id="rtoc-2" >困ったこと</h2>
<p><span class="sc_marker blue"><strong>ControllerやViewでURL生成を行うと現在のoriginを見るのですが、Commandクラスなどoriginを見れないものは明示的にオプションを示さないといけないのがCakePHPの掟です。</strong></span></p>
<p>今回の目的である、CommandクラスからHTTPS化されたURLを添付するにはどうしたらいいかというと、マニュアルのとおりに、生成時のオプションにHTTPSの指定をする必要がある。</p>
<blockquote><p>_https true にすると普通の URL から https に変換します。 false にすると、強制的に http になります。</p>
<p><cite class="blockquote_ref"> <a href="https://book.cakephp.org/4/ja/development/routing.html#id25" target="_blank" rel="noopener noreferrer">URL の生成</a> </cite></p></blockquote>
<pre class="line-numbers"><code class="language-php">$routes-&gt;url([
    'controller' =&gt; 'コントローラー名',
    'action' =&gt; 'アクション名',
    '_https' =&gt; true,
]);</code></pre>
<p>&nbsp;</p>
<p>これだけでHTTPSを指定できるのは、便利だなと思った矢先、HTTPSになっていない。</p>
<p>Routerクラスのインポート、スペルミスなどを確認してもHTTPS化ができていない。</p>
<p>&nbsp;</p>
<p>どうしてもHTTPS化が必須の要件だった、CakePHP3のマニュアルも読んでみた。</p>
<p><strong>驚きの展開だったのが、Cake3とCake４でオプションの内容が違うことがわかった。</strong></p>
<blockquote><p>_ssl true にすると普通の URL から https に変換します。 false にすると、強制的に http になります。</p>
<p><cite class="blockquote_ref"> <a href="https://book.cakephp.org/3/ja/development/routing.html#id23" target="_blank" rel="noopener noreferrer">URL の生成</a> </cite></p></blockquote>
<p>&nbsp;</p>
<p>以下の形で指定すると今回の目的を達成することができた。</p>
<pre class="line-numbers"><code class="language-php">$routes-&gt;url([
    'controller' =&gt; 'Articles',
    'action' =&gt; 'index',
    '_ssl' =&gt; true,
]);</code></pre>
<p>&nbsp;</p>
<p>枯れた技術を使うのはちょっと手間がかかりますねぇ。</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1731/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>LaravelにVueコンポーネントをバインドする方法</title>
		<link>https://otonan-syusyoku.work/archives/1720</link>
					<comments>https://otonan-syusyoku.work/archives/1720#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Mon, 15 Apr 2024 14:06:40 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[SPA]]></category>
		<category><![CDATA[Vue]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1720</guid>

					<description><![CDATA[Laravelプロジェクトを運用している方が jQuery を卒業して Vue または React を導入したい！という悩みに直面する事はしばしばあると思います。 SPAを構築するのはコスト的に対応が難しいため、Lara [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Laravelプロジェクトを運用している方が<span class="sc_marker blue"><strong> jQuery を卒業して Vue または React を導入したい！</strong></span>という悩みに直面する事はしばしばあると思います。</p>
<p>SPAを構築するのはコスト的に対応が難しいため、Laravelプロジェクトの一部にVueを導入する方法を解説しまっす。</p>
<div id="rtoc-mokuji-wrapper" class="rtoc-mokuji-content frame4 preset3 animation-fade rtoc_open noto-sans" data-id="1720" data-theme="BlogArise">
			<div id="rtoc-mokuji-title" class=" rtoc_center">
			<button class="rtoc_open_close rtoc_open"></button>
			<span>Contents</span>
			</div><ol class="rtoc-mokuji decimal_ol level-1"><li class="rtoc-item"><a href="#rtoc-1">環境</a></li><li class="rtoc-item"><a href="#rtoc-2">やりたいこと</a></li><li class="rtoc-item"><a href="#rtoc-3">手順</a><ul class="rtoc-mokuji mokuji_ul level-2"><li class="rtoc-item"><a href="#rtoc-4">なにわともあれVueのインストール</a></li><li class="rtoc-item"><a href="#rtoc-5">vite.config.js の設定</a></li><li class="rtoc-item"><a href="#rtoc-6">app.jsを使える状態に持っていく</a></li><li class="rtoc-item"><a href="#rtoc-7">マウント先の指定</a></li><li class="rtoc-item"><a href="#rtoc-8">コンポーネントの作成</a></li><li class="rtoc-item"><a href="#rtoc-9">コンポーネントの呼び出し</a></li></ul></li><li class="rtoc-item"><a href="#rtoc-10">最後に</a></li></ol></div><h2 id="rtoc-1" >環境</h2>
<ul>
<li>PHP8.2</li>
<li>Laravel10</li>
<li>Vue3
<ul>
<li>node v18.19.1</li>
<li>npm 10.5.0</li>
</ul>
</li>
</ul>
<h2 id="rtoc-2" >やりたいこと</h2>
<p>Laravel10の一部にVue.jsを適用する</p>
<ul>
<li>Vueコンポーネントを定義する</li>
<li>Vueコンポーネントをバインドする</li>
<li>Vueコンポーネントにバックエンドからデータを渡す</li>
</ul>
<h2 id="rtoc-3" >手順</h2>
<p><img decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO.png" alt="Let&#96;s GO" width="1000" height="500" class="aligncenter size-full wp-image-1680" srcset="https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO.png 1000w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO-300x150.png 300w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO-768x384.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p>
<h3 id="rtoc-4" >なにわともあれVueのインストール</h3>
<p>LaravelはビルドツールにViteを採用しているため、ViteのプラグインとしてVueをインストールします。<br />
（CLIでインストールしても良いと思いますよ！</p>
<pre class="line-numbers"><code class="language-other">$ npm install @vitejs/plugin-vue

<span>$ npm install @vitejs/plugin-vue --save-dev</span></code></pre>
<h3 id="rtoc-5" >vite.config.js の設定</h3>
<p>インストールしたVueを設定ファイルに追記します</p>
<pre class="line-numbers"><code class="language-js">import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue'; // 追記

export default defineConfig({
  plugins: [vue()] // 追記
});</code></pre>
<h3 id="rtoc-6" >app.jsを使える状態に持っていく</h3>
<p>Vueコンポーネントをグローバルコンポーネントとして登録するために、以下の形でapp.jsを編集します。</p>
<p>下記の記述でやりたいこととしては、<span class="sc_marker blue"><strong>コンポーネントの作成及びコンポーネントのマウント</strong></span>です。</p>
<pre class="line-numbers"><code class="language-js">import './bootstrap';
import {createApp} from 'vue';
import Alpine from 'alpinejs';
import VueDatePicker from './Components/Utility/CsrfToken.vue';
import VueDatePicker from './Components/Utility/DatePicker.vue';
import AddSalesListModal from "./Components/AddSalesListModal.vue";

window.Alpine = Alpine;

Alpine.start();

const app = createApp({});

// グローバルコンポーネント
app.component('csrf-token', CsrfToken);
app.component('add-sales-list-modal', AddSalesListModal);
app.component('date-picker', VueDatePicker);

// #appにマウント
app.mount('#app');
</code></pre>
<p>&nbsp;</p>
<h3 id="rtoc-7" >マウント先の指定</h3>
<p>app.js でマウント先を id=&#8217;app&#8217; としたため、以下のように blade ファイルにマウント先となる記述を設定します。</p>
<pre class="line-numbers"><code class="language-php">&lt;body id="app" class="font-sans antialiased flex flex-col min-h-screen"&gt;
~
~
~
&lt;/body&gt;</code></pre>
<h3 id="rtoc-8" >コンポーネントの作成</h3>
<p>試しにLaravelで生成されるCSRFトークンを扱うコンポーネントを作成します。</p>
<p>このコンポーネントはaxios等で非同期通信を実装するときなどに重宝されるはずですので、皆さんも作っておくと便利ですよん。<br />
（今回は擬似的にpタグにCSRFトークンを出力していますが、本来はしません</p>
<pre class="line-numbers"><code class="language-js">&lt;script&gt;
import { ref, onMounted } from 'vue';

export default function useCsrfToken() {
    const csrfToken = ref('');

    onMounted(() =&gt; {
        const token = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
        if (token) {
            csrfToken.value = token;
        }
    });

    return csrfToken;
}
&lt;/script&gt;

&lt;template&gt;
&lt;p&gt;{{ csrfToken }} &lt;/p&gt;
&lt;/template&gt;</code></pre>
<h3 id="rtoc-9" >コンポーネントの呼び出し</h3>
<p>以下の通りに記述したらVueで取得したCSRFトークンが出力されているはずですぅぅ</p>
<pre class="line-numbers"><code class="language-php">&lt;csrf-token&gt;&lt;/csrf-token&gt;</code></pre>
<p>Vueにバックエンドのデータを渡したいときには、以下の通りに実装してみてください</p>
<pre class="line-numbers"><code class="language-other">// Blade
&lt;csrf-token :test='@json($test)'&gt;&lt;/csrf-token&gt;

// Vue
&lt;script setup&gt;
import { defineProps, ref } from "vue";

const props = defineProps({
    test: Object,
});
&lt;/script&gt;</code></pre>
<h2 id="rtoc-10" >最後に</h2>
<p>SPAカッコいいから時間さえあればSPA化したい。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1720/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
