<?xml version="1.0" encoding="UTF-8" ?>
<feed xml:lang="ja" xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:thr="http://purl.org/syndication/thread/1.0">
  <title type="text">SHIRANGANA</title>
  <subtitle type="html">エンジニア日記</subtitle>
  <link rel="self" type="application/atom+xml" href="https://shirangana.omaww.net/atom"/>
  <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/"/>
  <updated>2015-09-24T15:16:50+09:00</updated>
  <author><name>YA</name></author>
  <generator uri="//www.ninja.co.jp/blog/" version="0.9">忍者ブログ</generator>
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" />
  <entry>
    <id>shirangana.omaww.net://entry/29</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/%E6%9C%AA%E9%81%B8%E6%8A%9E/%E7%A7%BB%E8%BB%A2%E3%81%AE%E3%81%8A%E7%9F%A5%E3%82%89%E3%81%9B" />
    <published>2017-05-29T18:20:48+09:00</published> 
    <updated>2017-05-29T18:20:48+09:00</updated> 
    <category term="etc" label="etc" />
    <title>移転のお知らせ</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[当ブログは下記に移転します。<br />
<br />
<a href="http://mugijiru.hateblo.jp/" title="" target="_blank">MUGIJIRU.JP</a>]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/28</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/laravel52/laravel%205.2%20csrf%20token%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF" />
    <published>2017-04-24T19:26:14+09:00</published> 
    <updated>2017-04-24T19:26:14+09:00</updated> 
    <category term="Laravel5.2" label="Laravel5.2" />
    <title>laravel 5.2 CSRF TOKENの仕組み</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[図にまとめたので上げておきます。<br />
要点は<br />
<br />
<span style="color: #ff0000;">・laravelのセッションはネイティブPHPのセッションを使っていない。</span><br />
<span style="color: #ff0000;">・cookieに設定される値は暗号化される。</span><br />
<span style="color: #ff0000;">・cookieに保存されるセッションid(laravel_session)とトークン(XSRF-TOKEN)はcookie名が違う。</span><br />
<span style="color: #ff0000;">・tokenはセッション作成時に発行され、regenerateしない限り不動。</span><br />
<span style="color: #ff0000;">・tokenをリクエストする方法は3通り(ヘッダ2パターン、パラメータ1パターン)ある。</span><br />
<br />
というところあたりだと思います。<br />
<br />
意外な落とし穴では<br />
<br />
・cookieの暗号化はenvのAPP_KEYがsaltに使われているので変更すると複合できなくなる<br />
・URL毎にlaravel_sessionにあたるcookie名を分けている場合、XSRF-TOKENも揃えないと意味がない<br />
　(x-csrf-token, _tokenだけで制御されているなら不要ですが)<br />
・<span style="color: #ff0000;"><strong>XSRF-TOKENのcookieの有効期限がなぜかソースに直書きになっているので</strong></span><br />
<span style="color: #ff0000;"><strong>　期限を伸ばすならばオーバーライドが必要</strong></span><br />
&nbsp; &nbsp;&nbsp;https://teratail.com/questions/27003<br />
<br />
という点が挙げられます。<br />
<br />
<a target="_blank" href="//shirangana.omaww.net/File/laravel_token.png" title=""><img src="//shirangana.omaww.net/Img/1493029546/" alt="" /></a>]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/27</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/laravel52/laravel%E3%81%A7expire_on_close%E3%82%92tr" />
    <published>2017-04-24T19:03:41+09:00</published> 
    <updated>2017-04-24T19:03:41+09:00</updated> 
    <category term="Laravel5.2" label="Laravel5.2" />
    <title>Laravelでexpire_on_closeをtrueにしているのに放置しているとセッションが切れる</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[<div><span style="font-size: small; color: #3366ff;"><strong><span style="color: #000000;">CSRF TOKENと関わりの深い話題だと思うので[<a href="http://shirangana.omaww.net/laravel52/laravel%205.2%20csrf%20token%E3%81%AE%E4%BB%95%E7%B5%84%E3%81%BF" title="" target="_blank">こちら</a>]もどうぞ。</span><br />
<br />
「せや！セッション持続時間を永続化したろ！」</strong></span></div><div><span style="font-size: small; color: #3366ff;"><strong>「expire_on_close = true！これで放置しても大丈夫やで！」</strong></span></div><div>&nbsp;</div><div>〜約2時間後〜</div><div>&nbsp;</div><div><span style="font-size: small; color: #3366ff;"><strong>SE「消えたンゴ」</strong></span></div><div><span style="font-size: small; color: #3366ff;"><strong>PG「ワイは消えてない・・・なぜなのか」</strong></span></div><div>&nbsp;</div><div>という状況の解決策をシェアしたいと思います。</div><div>&nbsp;</div><h3>解決策:</h3><div><span style="font-size: small; color: #ff0000;">lifetimeを長めに取ってみて下さい。</span></div><div>gc(ガベージコレクション)がセッションデータを削除しているかもしれません。</div><h4>expire_on_closeがtrueならlifetimeは無視されると思いきや・・・&nbsp;</h4><div><span style="font-size: small; color: #ff0000;">実はガベージコレクションの判定では使用されています。</span><br />
<br />
LaravelもネイティブPHPも、セッションデータを失う条件は</div><div>&nbsp;</div><div><strong>1.cookieが削除された</strong></div><div><strong>2.セッション自体の有効期限が切れた</strong></div><div><strong>3.gcが発動した</strong></div><div>&nbsp;</div><div>の3通りが主で、Laravelの場合1と2はexpire_on_closeで対応できますが</div><div><span style="font-size: small; color: #ff0000;">3はlifetime + lotteryの設定で動作する</span>ようになっています。</div><div>&nbsp;</div><div>要するに、<span style="font-size: small; color: #ff0000;">expire_on_closeがtrueでセッション自体の有効期限を永続化しても</span></div><div><span style="font-size: small; color: #ff0000;">ガベージコレクションが起こればデータが削除される場合がある</span>ということです。</div><div>&nbsp;</div><div>例えば、lifetimeが120、lotteryが[2, 100]であるならば</div><div>そのサーバに誰かからアクセスされる度、</div><div><strong>2/100(=2%)の確率で2時間以上更新されていないセッションデータを削除する</strong>という動きをします。</div><div>(消えたり消えなかったりのムラはこの確率判定が原因です)</div><div>&nbsp;</div><div><span style="font-size: small; color: #808080;">極端な話、</span><span style="font-size: small; color: #808080;">lifetime = 1 /&nbsp;</span><span style="font-size: small; color: #808080;">lottery = [100, 100]</span><span style="font-size: small; color: #808080;">にすると、<br />
expire_on_close = trueでも</span></div><div><span style="font-size: small; color: #808080;">1分以内にアクセスしなければセッションが吹っ飛ぶ様を見ることができます。</span></div><div>&nbsp;</div><div>放置されがちなアプリなら2時間は短いと思うので、例えば</div><div>「1週間触られていないセッションデータはさすがにゴミデータですよね」というポリシーなら</div><div>lifetimeは 60分 x 24時間 x 7日 = <strong>10080</strong></div><div>等と設定すれば良いと思います。</div><div>&nbsp;</div><div>gcを緩めすぎてデータ量が肥大化しないよう、</div><div>アプリの用途と規模を考慮し、用法用量を考えて正しくご設定くださいませ。</div><div>&nbsp;</div><div>&nbsp;</div>]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/25</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/tech/form%20submission%20canceled%20b" />
    <published>2017-02-07T18:59:14+09:00</published> 
    <updated>2017-02-07T18:59:14+09:00</updated> 
    <category term="技術" label="技術" />
    <title>Form submission canceled because the form is not connected</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[<div>最近から、ChromeにおいてjQueryでformをsubmit処理をするとき</div>
<div>「<span style="color: #ff9900;">Form submission canceled because the form is not connected</span>」</div>
<div>というメッセージがコンソールに出るようになり、submitができなくなることがあります。</div>
<div>&nbsp;</div>
<div>これはChromeのバージョン55系までは出ておらず、56系から出るようになりました。</div>
<div>(発生した私の環境では56.0.2924.87 64-bitでした)</div>
<div>&nbsp;</div>
<div>このエラーは、<strong>ブラウザが描画しているdocumentに埋め込まれていないformを</strong></div>
<div><strong>submitしようとするときに発生</strong>します。</div>
<div>&nbsp;</div>
<div>端的に言うと下記のような感じ</div>
<div><span style="color: #339966;">$('&lt;form action="hoge"&gt;&lt;/form&gt;').submit();</span> // これは上記のメッセージが出る。</div>
<div>&nbsp;</div>
<div>暫定の対応としては、</div>
<div>form要素をdocumentに一度埋め込むことによって動作するようになります。</div>
<div>&nbsp;</div>
<div>たとえば</div>
<div>&nbsp;</div>
<div><span style="color: #339966;">var form = $('&lt;form action="hoge"&gt;&lt;/form&gt;');</span></div>
<div><span style="color: #339966;">var temp_wrapper = $('div#temp');</span></div>
<div>&nbsp;</div>
<div><span style="color: #339966;">temp_wrapper.empty().append(form);</span></div>
<div><span style="color: #339966;">form.submit();</span> // 正常にsubmitされる。</div>
<div>&nbsp;</div>
<div>みたいな感じ。</div>
<div>&nbsp;</div>
<div>理由は、<strong>HTMLの仕様がそうであるから</strong>でした。</div>
<div>&nbsp;</div>
<div><strong><a href="https://www.w3.org/TR/html5/forms.html#form-submission-algorithm" title="" target="_blank">4.10.21.3 Form submission algorithm</a></strong></div>
<div>上項の2番に書いてあるとおりで、documentに結合していない要素の処理は無視されます。<br />
chromeはver56系からこれに従ったため、メッセージが出るようになったと思われます。</div>
<div>&nbsp;</div>
<div>以前から、このテクニックは裏技っぽい使い方だな、と思っていましたが、</div>
<div><strong>実際にブラウザハックだった</strong>ということになりますね！</div>
<div>正式な仕様としてはNGということになります。</div>
<div>&nbsp;</div>
<div>普段何気なく使っているHTMLですが、</div>
<div>不具合を出してお客さんに迷惑をかけたり、恥ずかしい思いをしないためにも</div>
<div>一度くらいは通しで規約を読んだほうが良さそうですね。</div>
<div>&nbsp;</div>
<div>参考URL</div>
<div><a href="http://stackoverflow.com/questions/42053775/getting-error-form-submission-canceled-because-the-form-is-not-connected" title="" target="_blank">Getting Error &ldquo;Form submission canceled because the form is not connected&rdquo;</a></div>]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/18</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/laravel52/laravelcollective-html%20ver5.2" />
    <published>2016-07-26T16:17:24+09:00</published> 
    <updated>2016-07-26T16:17:24+09:00</updated> 
    <category term="Laravel5.2" label="Laravel5.2" />
    <title>LaravelCollective/Html Ver5.2</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[<p>いつもお世話になっているHtml, Formの生成ヘルパーである LaravelCollective/Html<br />
Laravelのコアから外れた今でも、その利便性が褪せることはありません。</p>
<p>しかしながら、その機能の中で、今までどうしても不満に思っていた点がありました。<br />
それは、<span style="color: #ff0000;">Form Model Bindingをする時に</span><br />
<span style="color: #ff0000;"> 日付がCarbonである場合、テキスト出力される際にフォーマットが指定できず、</span><br />
<span style="color: #ff0000;"> テキスト欄に強制的にY-m-d H:i:sと出てきてしまっていた点</span>です。</p>
<p><strong>なぜここだけこんなにも融通が利かないんだろう。</strong><br />
という印象を受けた人は一人ではないのではないかと思います。</p>
<p>私も、dateと datetimeメソッドをフォーマット指定が可能なように<br />
拡張したクラスを作成しようか何度も迷っていました。</p>
<p><strong>最近もまた、そんなことを考えていたところ！</strong></p>
<p><strong>Ver5.2から新機能が追加されてた。</strong><br />
<span style="color: #ff0000;">FormModelBinding専用のアクセサが実装できるようです。</span></p>
<p>このように書くことができるようになります。(公式より抜粋)<br />
<a href="https://laravelcollective.com/docs/5.2/html#form-model-accessors" title="" target="_blank">https://laravelcollective.com/docs/5.2/html#form-model-accessors</a></p>
<pre class="brush: php">namespace App;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Get the user's first name.
     *
     * @param  string  $value
     * @return string
     */
    public function getDateOfBirthAttribute($value)
    {
        return Carbon::parse($value)---&gt;format('m/d/Y');
    }

    /**
     * Get the user's first name for forms.
     *
     * @param  string  $value
     * @return string
     */
    public function formDateOfBirthAttribute($value)
    {
        return Carbon::parse($value)-&gt;format('Y-m-d');
    }
}
</pre>
<p><span style="color: #ff0000;">formDateOfBirthAttribute</span> が専用アクセサですね。<br />
(getDateOfBirthAttributeはもともとあるEloquentのアクセサです)</p>
<p>まだ自由自在になりきったというところまではいかないものの、<br />
普段使いで露骨に不足しない程度にはなってきたのではないかと思います。</p>
<p>ありがたいことです。</p>]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/16</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/laravel5.1/laravel5.1%20%E3%82%BB%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3%20flash%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9" />
    <published>2016-05-31T19:17:02+09:00</published> 
    <updated>2016-05-31T19:17:02+09:00</updated> 
    <category term="Laravel51" label="Laravel51" />
    <title>Laravel5.1 セッション flashの注意点</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[久しぶりのLaravel話です。<br />
<br />
Laravelではエラーメッセージの表示などで馴染み深い<strong>flashセッション</strong>の機能がありますが<br />
この機能は「<strong>次回のリクエストまでセッションを維持する</strong>」という<span style="color: #ff0000;">言葉の通り動作</span>します。<br />
<br />
もし次回のリクエストでflashセッションを引き続き維持したい時は、<br />
<strong>遷移やアクセスの可能性を十分に理解・整理したうえで、</strong><br />
<br />
Input::flash();<br />
<br />
や<br />
<br />
$request-&gt;session()-&gt;reflash();<br />
<br />
をうまく使いましょう。<br />
<br />
繰り返しますが、この言葉の通りなので使う時は<span style="color: #ff0000;">ちゃんとわかって使う事が大事</span>だったりします。<br />

<h3>はまりがちな罠 - 1</h3>
APIなどの非同期通信で消えてしまう。<br />

<h3>はまりがちな罠 - 2</h3>
public以下に設置したcss, js, imgの404アクセス(laravelのハンドラで処理)で消えてしまう。<br />

<h3>そんなことがあるのか的な罠(これが言いたかった)</h3>
<span style="color: #ff0000;">barryvdh/laravel-debugbar を噛ませている場合、エラーハンドリング時は暗黙にreflashされるので</span><br />
<span style="color: #ff0000;">.envのdebug=falseで本番デプロイするまで上記の罠 - 2が表面化しない！！！</span><br />
<br />
debug=trueの時に導入される便利ツールたちは便利ではありますが<br />
こういう思いがけない事例もあるのだと感心しました。<br />
<br />
flash自体は良い仕組みですので使いこなしていきたいところですが、<br />
ちゃんとケースバイケースで用途を考えて実装する必要がありますね。<br />
エラーハンドラ内で404であればreflashするとか、<br />
APIのミドルウェアで特定の条件でのみreflashするとか、<br />
安直に思いつく手はあれど、十分にケースを網羅した上で正解を決めていきたいところです。<br />
<br />
この調査のためにまたソースをたくさん読んだので、良い勉強になりました。]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/13</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/laravel5.1/laravel5.1%20collection%E3%81%AE%E6%B3%A8%E6%84%8F%E7%82%B9" />
    <published>2016-02-03T19:07:32+09:00</published> 
    <updated>2016-02-03T19:07:32+09:00</updated> 
    <category term="Laravel51" label="Laravel51" />
    <title>Laravel5.1 collectionの注意点</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[<p>Laravel小ネタ。</p>
<p>Laravelで用意されている便利な配列操作オブジェクト「collection」<br />
これを使用している中で、人によってはハマりそうなケースを発見しました。</p>
<h2>こんなことがあったのです</h2>
<pre class="brush: php">// EloquentのCollectionをゲット。
$persons = App\Person::all();

// あるカラムだけのCollectionにして、重複を排除してみよう。
$nicknames = $persons-&gt;pluck('nickname')-&gt;unique();
</pre>
<p>（ ゜Д゜）あれー</p>
<pre style="color: red;">[Symfony\Component\Debug\Exception\FatalThrowableError]
Fatal error: Call to a member function getKey() on integer
</pre>
<p>普通に重複を排除した値を取ってくれるなら問題ないんですが<br />
エラーで落ちてしまいました。</p>
<h2>とりあえず結論から</h2>
<p>Eloquentから得たCollectionは<br />
「Illuminate\Database\Eloquent\Collection」<br />
を使っている。</p>
<p>実はこれ、Illuminate\Support\Collection と似ているが、ちょっと違う。<br />
このオブジェクトは所属アイテムがEloquentのModelオブジェクトである事を想定しているようだ！</p>
<p>よって、pluck()等でEloquentオブジェクト以外が所属している状態になった場合は<br />
使うメソッドによっては、エラーになるぞ！</p>
<h2>エラーの解決策</h2>
<p>Modelのcollectionとして使用しないのなら、混同しないこと。<br />
明示的にIlluminate\Support\Collection オブジェクトにして扱えばよろしい。</p>
<pre class="brush: php">    $nicknames = collect($persons-&gt;pluck('nickname'))-&gt;unique();
</pre>
<h2>ちなみに</h2>
<p>エラーが発生した場所のコードはこちら。</p>
<pre class="brush: php">/**
 * Return only unique items from the collection.
 *
 * @param  string|callable|null  $key
 * @return static
 */
public function unique($key = null)
{
    if (! is_null($key)) {
        return parent::unique($key);
    }

    return new static(array_values($this-&gt;getDictionary()));
}
</pre>
<p>からの、</p>
<pre class="brush: php">/**
 * Get a dictionary keyed by primary keys.
 *
 * @param  \ArrayAccess|array  $items
 * @return array
 */
public function getDictionary($items = null)
{
    $items = is_null($items) ? $this-&gt;items : $items;

    $dictionary = [];

    foreach ($items as $value) {
        // ここ！！$itemにgetKey()が実装されている事が前提になっている。
        // getKeyは、Eloquent Modelのプライマリキーのカラム名を返すメソッド。
        $dictionary[$value-&gt;getKey()] = $value;
    }

    return $dictionary;
}
</pre>
<p>Laravelはソースがきれいなのですぐ分かります。<br />
なるほどね、と思ったのでした。</p>]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/10</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/laravel5.1/laravel%E3%81%AE%E4%BE%BF%E5%88%A9%E3%81%AAvalidtion" />
    <published>2015-11-30T23:30:27+09:00</published> 
    <updated>2015-11-30T23:30:27+09:00</updated> 
    <category term="Laravel51" label="Laravel51" />
    <title>Laravelの便利なValidationルール</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[<p>LaraveのValidationは大変使いやすいです。<br />
業務システムを作るとき、わりと使いやすいけど調べてもわかりにくいルールを 備忘録として書いておきます。</p>
<p><strong>unique</strong><br />
よくある重複チェック。DB内を検索してくれます。<br />
すべての検索条件が=(イコール)でチェックできるならこんな書き方ができます。</p>
<pre class="brush: php">&lt;?php
// 必須ですよ|自分のid以外のcompany_idとshop_idが同じ商品の中でユニークじゃないとだめですよ
$rules = [
    'item_code' =&gt; 'required|unique:items,item_code,'.$my_id.',id,company_id,'.$my_company_id.',shop_id,',$my_shop_id;
];
</pre>
<p>実際は下記の構成になっています。<br />
unique:{テーブル名},{対象カラム名},{除外条件の値},{&larr;のカラム名(id等)},{where カラム1},{&larr;の値},{and カラム2},{&larr;の値}, ...</p>
<p><strong>required_if</strong><br />
一緒に渡されたパラメータの値を見て、特定の条件だったら必須とする。</p>
<pre class="brush: php">&lt;?php
// 数字ですよ|typeがstudentの時だけ必須ですよ
$rules = [
    'age' =&gt; 'numeric|required_if:type,student';
];
</pre>
<p><strong>before (after)</strong><br />
日付に適用できるフィルタ。以前、以後を表現できる。</p>
<pre class="brush: php">&lt;
?php
// 必須ですよ|日付ですよ|今日より前である必要がありますよ
$rules = [
    'birth_date' =&gt; 'required|date|before:'.date('Y-m-d');
];
// 一緒に渡されたto_dateより前である必要がありますよ
$rules = [
    'from_date' =&gt; 'date|before:to_date';
];
</pre>
<p>ちなみに、たいていValidationのルール定義はFormRequest内のrules()メソッドで返すのが定石ですが<br />
特殊な入力フローを使っていて、Controller等でValidationを行いたい時もあると思います。<br />
そんな時はこんな感じでもかけます。</p>
<pre class="brush: php">&lt;?php
// 手動でValidatorを作るよ
$validator = Validator::make($params,  [
    // rules...
]);
// Validateしてエラーがあったら
if ($validator-&gt;fails()) {
    // エラーメッセージと入力された値を持って入力画面に戻るよ
    return redirect()-&gt;route('edit_page_route_name')-&gt;withErrors($validator)-&gt;withInput();
}
</pre>
<p>Laravelのすごいところは、たいていの事を網羅してくれているところだと思います。<br />
Laravelの実装機能の範囲内で対応できない要件は、完全に特殊な入力をする必要があるか<br />
そもそもの考え方や設計がおかしいかのどちらかなので、<br />
書いていく中で「行き詰まる事」が「状況整理のタイミング」として<br />
考えず書き進めるような事を避ける癖が付いていくのが嬉しいですね。</p>]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/7</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/php/array_get" />
    <published>2015-10-31T21:51:17+09:00</published> 
    <updated>2015-10-31T21:51:17+09:00</updated> 
    <category term="PHP" label="PHP" />
    <title>array_get</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[phpにおいて所々で自作される「array_get」は大変便利な関数です。<br />
Laravelのhelperにも入っています。<br />
<br />
一般的な実装としては、「配列から与えられたキーの値を返す」というシンプルなもので、<br />
たいていは3つの引数をとります。<br />
<br />
第1引数 = 配列<br />
第2引数 = キー<br />
第3引数 = 値がなかった場合に返す値<br />
<br />
Laravelはドット区切りの設定ファイルを取り扱うので、<br />
'hoge.fuga' なんてキーを渡すと<br />
$array['hoge']['fuga']<br />
を探してくれるようなものを実装したりしていますね。<br />
<br />
私も業務アプリを書くことが多かったので<br />
多重の配列を取り扱うことが多く、階層を掘れるarray_getがほしい場面がたまにありました。<br />
掘る階層の位置を動的に変える事に対応するため、引数に配列を許可し、<br />
配列を許可した場合はその順番に階層を掘るという動きをさせるようにしました。 自作したソースは下記です。<br />
<br />
<br />

<pre class="brush: php">&lt;?php
/**
 * array_get の再帰版
 *
 * 配列$arrayのキー$key(数値 or 文字 or 配列)の値を取得する。
 * 配列で指定した場合、要素の順番に配列を掘っていく。
 * 例外が発生した場合$defaultを返す。
 *
 * @param array $array   探す配列
 * @param mixed $key     探すキー。階層を掘る場合は配列で指定する
 * @param mixed $default 値がなかった場合に返すデフォルト値
 *
 * $array['key1']['key2']['key3'] の値が欲しければ
 *
 * $key = array('key1', 'key2', 'key3');
 * $value = aget($array, $key); と書ける。
 */
function aget($array, $key, $default = null) {
    if (!is_array($key)) {
        return is_array($array) &amp;&amp; array_key_exists($key, $array) ? $array[$key] : $default;
    }

    if (!$key) return $default;

    foreach ($key as $k) {
        if (is_array($array) &amp;&amp; array_key_exists($k, $array)) {
            $array = $array[$k];
        } else {
            return $default;
        }
    }

    return $array;
}
</pre>
同時に、階層を調整して値を設定したい場面もありました。<br />
setter版も作成しました。
<pre class="brush: php">&lt;?php
/**
 * aget のsetter版
 *
 * 配列$arrayのキー$key(数値 or 文字 or 配列)に値$valueを代入する。
 * 配列で指定した場合、要素の順番に配列を掘っていく。
 * 値がnullであった場合、[] として扱う。
 *
 * $array['key1']['key2']['key3'] = $value は
 *
 * $pos = array('key1', 'key2', 'key3');
 * aset($array, $pos, $value); と書ける。
 *
 * 値の設定に成功した場合、trueを返す。
 */
function aset(&amp;$array, $key, $value)
{
    if (!is_array($array)) {
        return false;
    }
    if (!is_array($key)) {
        if ($key === null) {
            $array[] = $value;
        } else {
            $array[$key] = $value;
        }
    } else {
        if (!$key) return false;
        $ref = &amp;$array;
        foreach ($key as $k) {
            if ($k === null) {
                $ref = &amp;$ref[];
            } else {
                $ref = &amp;$ref[$k];
            }
        }
        $ref = $value;
        unset($ref, $array);
    }

    return true;
}
</pre>
昔のソースを引っ張り出してきたので、出来は不明ですが・・・<br />
複雑な配列構造の操作において、可読性にかなり貢献してくれた関数たちです。]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
  <entry>
    <id>shirangana.omaww.net://entry/5</id>
    <link rel="alternate" type="text/html" href="https://shirangana.omaww.net/tech/20150930" />
    <published>2015-10-07T20:02:15+09:00</published> 
    <updated>2015-10-07T20:02:15+09:00</updated> 
    <category term="技術" label="技術" />
    <title>DIって何だろう？</title>
    <content mode="escaped" type="text/html" xml:lang="utf-8"> 
      <![CDATA[<pre class="brush: php">&lt;?php
/*
 
DIってなんだろう？

「依存性の注入」だそうで。
ソースコードの保全性向上とか、メンテナンスやらテストが綺麗にできるようになる
という事は聞いている。

単純な計算プログラムでも作って実感してみよう！

まずは、レガシーな書き方をしてみる。

Calcっていうクラスがあって、その中に各計算用のメソッドを用意して、
制御側でメソッドを呼び分けるという愚直なスタイル。

 */

// 計算するクラスだよ
class Calc
{
	// 足し算するとき呼んでね
	public function execAdd($left, $right)
	{
		return $left + $right;
	}
	// 引き算するとき呼んでね
	public function execDiv($left, $right)
	{
		return $left / $right;
	}
}

// では早速使ってみよう。「Add」か「Div」という文字を渡すと計算してくれるなかなかのやつ


$method = 'Add'; // 足し算をしよう
$left   = 10;    // 左辺は10
$right  = 5;     // 右辺は5としよう

// 計算機のお出ましだ
$calc = new Calc;

// 場合によって呼ぶメソッドを変えよう
if ($method === 'Add') {
	$answer = $calc-&gt;execAdd($left, $right);
} elseif ($method == 'Div') {
	$answer = $calc-&gt;execDiv($left, $right);
}


// とりあえず、$answerは15だった！




/*
 
まあ、こういう書き方は昔からありがちである。

なるほど、当然これだと処理が「Calcクラスの実装ありき」になってるので
Calcクラスのメソッド名とかが変更になれば、元の処理の流れも修正をしなきゃいけない。
計算ロジックを修正するときも、足し算割り算どちらにも関わらずこのクラスの書き換えが必要。

何をするにもCalc課長の重い腰を上げて頂く必要があるのだ。

＝依存性が強いとはこういうことか！

じゃあ、DIっぽくしてみよう。
「依存性の注入」的なものである。

そもそも、Calcクラスの役割は「計算する」という概念なわけで、
「何々の計算をする」という具体的な所まで包括するといろいろ詰め込みすぎてしまう。
いろんな用途で編集されうるクラスになってしまうということだ。

なので、シンプルに分けていくことにする。
Calc課長しかいろいろできないのは困るので、
「計算する！」というGoサイン出しまでを受け持ってもらい、
「何々の計算をする！」という細かい話は、部下の「モジュール」に分けてそれぞれに依存していこう。

 */

// 「何々の計算をする」にあたる、計算モジュールの実装フォーマット(interface)だよ。
// これを土台に、足し算や引き算を作って、CalcDIに「注入」するよ。
interface CalcModule
{
	// 計算モジュールには、とにかく「計算結果をくれ」というメソッドだけは必ず実装してね。
	// CalcDI課長が必ず呼ぶよ。
	public function getResult($left, $right);
}

// 計算モジュール「足し算」だよ
class CalcAdd implements CalcModule
{
	public function getResult($left, $right)
	{
		return $left + $right;
	}
}

// 計算モジュール「割り算」だよ
class CalcDiv implements CalcModule
{
	public function getResult($left, $right)
	{
		return $left / $right;
	}
}


// 計算をするクラスがDIっぽくなったよ。
// CalcさんからCalcDIさんに進化した！(実際はスーパー社員からハンコ押し係に格下げ)
// 計算部分は「モジュール」として別のクラスに分けていくよ。
class CalcDI
{
	// とにかく、「計算する！」はこれだけだ！
	// 計算を実行するときは常にこれを呼ぶだけでいいよ。
	// その代わり、$moduleに「何々の計算をする」にあたるモジュールをセットしてね。
        // あとCalcModuleの枠に従ってない部下は受け付けないからね！
	public function exec(CalcModule $module, $left, $right)
	{
		// 計算結果を返すね
		return $module-&gt;getResult($left, $right);
	}
}


// では、CalcDI版で足し算をしよう。
$method = 'Add'; // 足し算をしよう
$left   = 10;    // 左辺は10
$right  = 5;     // 右辺は5としよう

// 場合によって「何々の計算をする」部分だけを取り分けよう。
if ($method === 'Add') {
	$module = new CalcAdd;
} elseif ($method == 'Div') {
	$module = new CalcDiv;
}

// さあ計算だ
$calc   = new CalcDI;

// 「計算する！」をひたすら叫ぶだけのCalcDIさん
$answer = $calc-&gt;exec($module, $left, $right); 

// $answerは15だった！


/*
 
これでもうCalcDI課長は全体の処理で口火を切る「計算をする！」を叫ぶだけの係になり、
ごちゃごちゃ触れられる機会が激減した事が分かった。

計算の種類を増やしたり、計算の内容を変更するときは
それぞれのモジュールを調達したり編集するだけでよくなった。

ただ、まだモジュールの生成に分岐が入っていて実装側はだるいままである。
依頼者は、課長に仕事を依頼する前に望む処理ができる社員を自分で引っ張ってこなければならないのである。

ではここで、やりたいことを伝えれば勝手にモジュールを取ってきてくれる
Factory主任にお出ましいただこう

Factory主任「望みを言え！！さすれば適切な社員をアサインしてやる！」

 */



// ----------------------


// Factory主任だよ。計算モジュールをよしなに取ってくるすごいやつだよ
class CalcModuleFactory
{
	// 計算したい種類を教えてくれ！
	public function make($method)
	{
		// その種類なら、計算モジュールの名前はこれのはずだ！
		$moduleName = $this-&gt;getModuleName($method);

		// 一応計算モジュールがあるかどうか事前に調べておこう！
		$this-&gt;_checkModule($moduleName);

		// 計算モジュールが居たぞ受け取れ！！
		return new $moduleName;
	}

	public function getModuleName($method)
	{
		return 'Calc'.$method;
	}

	protected function _checkModule($moduleName)
	{
		if (!class_exists($moduleName)) {
			throw new Exception('計算の種類:'.$moduleName.'は未実装のようだ！');
		}
	}
}

// ではFactory主任に助けてもらって足し算を。
$method = 'Add';
$left   = 10; // 左辺
$right  = 5;  // 右辺


// 分岐もモジュール探しも全部Factory主任にお任せだ
$factory = new CalcModuleFactory;
$module  = $factory-&gt;make($method);

// ささっと計算！
$calc    = new CalcDI;
$answer  = $calc-&gt;exec($module, $left, $right);

// $answerは15だった！


/*

すばらしい。
これでもう、計算の種類を追加するときはモジュールを作るだけで良くなった。
他に触るべき処理もなくなってしまった。

CalcDI課長はモジュールと左辺と右辺をもらって「計算する！」を叫ぶだけであり、
渡すモジュールはFactory主任が勝手に連れてきてくれるし、
具体的な計算処理であるモジュールたちはinterfaceの秩序のもと足並みを揃えてお行儀良くしながら、
自分の処理に集中しているからである。

結局メインの処理は「目的(やりたい事)」と「材料(左辺と右辺)」を用意するだけで、
もう何も弄らなくて良くなってしまった。

やりたい事が増えても、モジュールを追加(スペシャリスト社員を雇用)するだけでいいのである。

以上で、DIの良さを実感し、なんとなくわかったつもりになれた。

なお、LaravelはDIの概念を掲げてソースを構築しているので、とても勉強になる。
自分も綺麗な実装ができるように日々精進する次第である。


以上でDIってなんだろう？は終了です。





p.s.
これだけ整頓されているとワンライナー化してドヤ顔することもできるぞ！
(ワンライナーは独りよがりにならない範囲で計画的に！)
*/

$answer = (new CalcDI)-&gt;exec((new CalcModuleFactory)-&gt;make($method), $left, $right);
</pre>]]> 
    </content>
    <author>
            <name>YA</name>
        </author>
  </entry>
</feed>