もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

Vue.js触ってみた(はじめに)

はじめに

こんばんは。

3post目です。しょっぱい記事ですが、自分の勉強のためにやってるから別にいいや。

Vue.jsってコード見たりサンプルみたりは比較的やってたのですが、自分で書いたことなかったんで、公式のサイトチュートリアル的なの触ってみようと思いました。

まずはこちらのはじめにページをやってみる。

やってみた

1. 宣言的レンダリング

<div id="app">
  {{ message }}
</div>
<script type="text/javascript">
var app = new Vue({
  el: '#app',
  data: {
    message: 'Vueやってみたよ。'
  }
});
</script>

f:id:kojirooooocks:20180514011209p:plain

f:id:kojirooooocks:20180514011223g:plain

consoleで値を変更すると、HTML内のmessageの文字列も変わるのが気持ちいい。

2. 属性をバインディングする(v-bind)

<div id="app">
    <span v-bind:data_name="message">Kojirock!!</span>
</div>

<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            message: "kojirock"
        }
    });
</script>

f:id:kojirooooocks:20180514011249p:plain

すばらしい。属性をバインディングするってこういうことか。

3. 条件分岐(v-if, v-else)

<div id="app">
    <span v-if="is_sleep">寝てますよ</span>
    <span v-else>寝てませんよ!!!</span>
</div>

<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            is_sleep: true
        }
    });
</script>

f:id:kojirooooocks:20180514011316p:plain

f:id:kojirooooocks:20180514011328p:plain

if - else文も問題なし

v-else-ifもあるみたいだけど、ココまで来たらなんとなく想像つくから抜かした。

4. ループ(v-for)

<div id="app">
    <div v-for="album in album_list">
        <p>{{ album.title }}</p>
        <ol>
            <li v-for="music in album.music_list">{{ music.name }}</li>
        </ol>
    </div>
</div>

<script type="text/javascript">
    var app = new Vue({
      el: '#app',
      data: {
        album_list: [
          { title: 'I co Y', music_list: [
              { name: "ソーダ" },
              { name: "ふっかつのじゅもん" },
              { name: "リグレット" }
          ] },
          { title: 'そりゃ弾けなくて', music_list: [
              { name: "ゾンビの祭り" },
              { name: "人間の歌" },
              { name: "世界平和ロックンロール" }
          ] },
          { title: 'DANCEABLE', music_list: [
              { name: "Oh Yeah" },
              { name: "Crazy Dancer" },
              { name: "By My Side" }
          ] },
          { title: 'thread', music_list: [
              { name: "Jungles" },
              { name: "その向こうへ" },
              { name: "hammer ska" }
          ] }
        ]
      }
    });
</script>

f:id:kojirooooocks:20180514011342p:plain

入れ子ループも問題なかった!!

5. ユーザー入力の制御(v-on)

<div id="app">
    <p>{{ message }}</p>
    <button v-on:click="changeMessage">占い実行</button>
</div>

<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            message: "当たるかな?"
        },
        methods: {
            changeMessage: function() {
                var result = Math.floor(Math.random() * Math.floor(2));
                if (result === 1) {
                    this.message = "おみごと!あたり"
                } else {
                    this.message = "残念!はずれ"
                }
            }
        }
    });
</script>

f:id:kojirooooocks:20180514011402g:plain

onclickがbuttonタグにセットされていると思いきや、buttonタグはなにもセットされてなかった。おもしろい

6. 双方向バインディング(v-model)

<div id="app">
    <p>{{ message }}</p>
    <input v-model="message">

    <p>{{ message_2 }}</p>
    <select v-model="message_2">
        <option value="test_select_1">テストセレクト1</option>
        <option value="test_select_2">テストセレクト2</option>
    </select>

    <p>{{ message_3 }}</p>
    <input type="radio" v-model="message_3" value="test_radio_1">テストラジオ1<br />
    <input type="radio" v-model="message_3" value="test_radio_2">テストラジオ2<br />

    <p>{{ message_4 }}</p>
    <input type="checkbox" v-on:click="changeMessage" value="test_check_1">テストチェックボックス1<br />
    <input type="checkbox" v-on:click="changeMessage" value="test_check_2">テストチェックボックス2<br />
    <input type="checkbox" v-on:click="changeMessage" value="test_check_3">テストチェックボックス3<br />
</div>


<script type="text/javascript">
    var app = new Vue({
        el: "#app",
        data: {
            message: "テストだよ",
            message_2: "テストだよ2",
            message_3: "テストだよ3",
            message_4: "テストだよ4",
            message_4_origin: "テストだよ4",
        },
        methods: {
            changeMessage: function(e) {
                if (e.target.checked === true) {
                    this.message_4 = e.target.value;
                } else {
                    this.message_4 = this.message_4_origin;
                }
            }
        }
    });
</script>

f:id:kojirooooocks:20180514011429g:plain

input以外にも色々やってみました。(checkboxはそのままではできなかった)

7. コンポーネント

<div id="app">
    <p>{{ message }}</p>
    <div>
        <ol>
            <biography-item v-for="biography in biography_list" v-bind:item="biography"></biography-item>
        </ol>
    </div>
</div>

<script type="text/javascript">
    Vue.component('biography-item', {
        props: ['item'],
        template: "<li>{{ item.name }}</li>"
    });

    var app = new Vue({
        el: "#app",
        data: {
            message: "クラプトンバンド遍歴",
            biography_list: [
                { name: "ヤードバーズ" },
                { name: "ブルースブレイカーズ" },
                { name: "クリーム" },
                { name: "ブラインド・フェイス" },
                { name: "デレク・アンド・ザ・ドミノス" }
            ]
        }
    });
</script>

f:id:kojirooooocks:20180514013451p:plain

こんな感じ。

公式サイトに乗せてくれていた、この画像がわかりやすかった。

f:id:kojirooooocks:20180514013502p:plain

つまりこういった、コンポーネント郡をいっぱい作って、組み合わせてサイトを構築していくという感じのようだ。

おわりに

しょっぱいけどココまで。

せっかく最初のページをやってみたから、続けて次のページからもやってみようとおもいます。

ReactNative少しだけやったので、Reactもやりたいんですが、そっちは仕事できそうなのでもう少し後から素振り開始しても良いかなと。

それよりも勢いのあるvueをやってみたかったので、今回は勉強になりました。

おわり。

プルリクレビュー必須にしてやった

参考サイト

はじめに

先日、お世話になっている会社のあるエンジニアさんが、緊急ということでプルリク後セルフマージするという事がありました。

そのエンジニアさんはドメイン知識も豊富な頼れるエンジニアさんなので、その方のセルフマージは許せますが、経歴が若いエンジニアさんにそういうことをやられると困ります。

なんか制限できないかなーといろいろ調べてたら、参考サイト様に出会いました。

ちょっとやってみます。

やってみた

参考サイト様におんぶにだっこでやってみます。

まずレポジトリの Setting から Branches を選択します。

f:id:kojirooooocks:20180511032646p:plain

Branch protection rules で 保護するブランチを選択します。

まぁ大体のプロジェクトは master かなと。

選択すると以下のような画面に遷移します。

f:id:kojirooooocks:20180511032657p:plain

Protect this branch をチェックすると諸々チェックボックスが現れます。

f:id:kojirooooocks:20180511032729p:plain

参考サイト様に詳しく書かれているんで、改めて説明することないですが、現在のプロジェクトに合いそうなものだけ説明していきます。

1. Require pull request reviews before merging

コチラが今回のやりたかったことのメイン。マージ前にレビューを必須にするという設定です。

チェック入れます。

するとなんかセレクトボックスが出てきました。

f:id:kojirooooocks:20180511032742p:plain

Required Approving reviewsと書いているので、おそらくプルリクに対してのApproveの数だと思います。

とりあえず1で。

2. Dismiss stale pull request approvals when new commits are pushed

Approveされた後更にコミットされた時に、再度レビュー挟むか?みたいな設定のようです。

これもチェック入れます。

3. Require review from Code Owners

コード所有者のレビューを必須にすると機能

基本的に自分のプルリクは自分がApprove出来ないようなので問題ないですが、やっぱり重要な人のレビューを通したいというのはあります。

.githubディレクトリに CODEOWNERS というファイルを追加して、コードの所有者を設定できます。

* @ユーザー名

とかってやると、指定のレポジトリが全て指定ユーザが所有者になります。

これもチェックしておきましょう!

4. Require status checks to pass before merging

CIなどでユニットテストを走らせて、それが通らないとマージできないようにするみたいなことが出来るようです。

現状お仕事先ではJenkinsを導入しているので使えるのですが、まだ連携できてません。なので今回は見送ります。

5. Require signed commits

署名済みコミットが必須になるチェックです。

自分はやっているんですが、他のエンジニアが設定しているかを確認しないといけないので、こちらも一旦見送ります。

6. Include administrators

管理者もマージ必須にするかどうかのチェックです。

これはどうするか悩むところです。。。

夜間の緊急対応などの考えるとチェックは付けたくないなと思います。

ただ、管理者の場合はこのルールの編集もできるので、そのときだけこのチェックを外せばよいのではと思います。

なので付けちゃいます!

ちなみに、この設定を付けるときと付けないときでどんな表示になるのかなと確認すると、以下のようになりました。

チェックを付けた場合

f:id:kojirooooocks:20180511032759p:plain

マージボタンが押せないようになってます。

チェックを付けない場合

f:id:kojirooooocks:20180511032813p:plain

f:id:kojirooooocks:20180511032908p:plain

赤い表示になっていますが、管理者なのでマージが実行できます。

ということで最終的に今回のルールは以下のようになりました。

f:id:kojirooooocks:20180511032922p:plain

おわりに

実際にどの程度、影響があるかどうかは試してみないとわかりませんが、github側でルールを作ってもらうことで、間違ってマージしちゃったなどもなくなるので、良い方向に転がると思っています。

今日はココまで。

お腹痛い。。。

minikubeでローカル環境作ろうとしてみた

はじめに

こんばんは。

先日こんな記事上げておいてあれですが、コチラの記事を発見しましたので、早速自分もやってみようと思いました。

まずKubernetesを入れてなかったので入れるとこからです。

やってみた

1. Kubernetesインストール

そもそも、Kubernetesってよく聞くけど何?って状況だったので調べると、コンテナ化したアプリケーションのスケーリングやら、管理やらの運用を自動化するツールということでした。

まだ??という感じですが、とりあえずは立てたコンテナアプリケーションをいい感じに管理運用できるツールということで覚えときます。

まずDockerFoMacのEdgeバージョンをインストールする必要があるので、

コチラで紹介されている方法で、インストールしました。

f:id:kojirooooocks:20180510070654p:plain

Preferences -> Kubernetesで、「Enable Kubernetes」をチェックしてApplyを実行します。

f:id:kojirooooocks:20180510070706p:plain

すると、kubectlコマンドを実行できるようになります。

$ which kubectl
/usr/local/bin/kubectl

これで完了です。

2. minikubeインストール

Kubernetesクラスタ環境をローカルで簡単に構築できるツールということです。

コチラからインストールできます。

自分はMacなので、コチラのコマンドでインストールします。

$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.26.1/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/

$ which minikube
/usr/local/bin/minikube

minikubeコマンドが実行できるようになってるので、minikube startで起動します。

初回は時間がかかりますが2回目からはそうでもないです。

$ minikube start
Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Downloading Minikube ISO
 150.53 MB / 150.53 MB [============================================] 100.00% 0s
Getting VM IP address...
Moving files into cluster...
Downloading kubeadm v1.10.0
Downloading kubelet v1.10.0
Finished Downloading kubelet v1.10.0
Finished Downloading kubeadm v1.10.0
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.

起動出来たら Kubernetesダッシュボード確認するため、以下のコマンドを実行してみます。

$ minikube dashboard

f:id:kojirooooocks:20180510070728p:plain

見えました!

かっこいい...

3. Komposeインストール

先日作ったdocker-composeの設定ファイルを使ってテストしてみたいのですが、KubernetesKubernetesの設定ファイルの記述方法があるようで、それはdocker-composeとは違うようです。

そんなdocker-composeの遺産を、よしなにKubernetes用の設定ファイルに変換してくれるのがKomposeです。

コチラからインストールできます。

自分はMacなので以下のコマンドでインストールしました。

$ brew install kompose
...
...
==> Summary
🍺  /usr/local/Cellar/kompose/1.12.0: 8 files, 43.9MB

$ which kompose
/usr/local/bin/kompose

brew入ってない場合はコチラに記載されている以下のやり方でもOKだと思います。

$ curl -L https://github.com/kubernetes/kompose/releases/download/v1.12.0/kompose-darwin-amd64 -o kompose

$ chmod +x kompose
$ sudo mv ./kompose /usr/local/bin/kompose

さっそく変換してみます。 変換するのは先日の記事で作成した以下のdocker-compose.ymlです。

コチラにも書かれているように、

ローカルでDockerレジストリを動かす Kubernetesにはコンテナイメージをビルドする機能はありません。 従って、サンプルアプリケーションのカスタムイメージをどこかのレジストリにpushし、そこからpullするように設定する必要があります。

ということです。

docker-hubにsanple_appとしてpushしてたimageをpullしてきます。

$ docker pull XXXXXXX/sample_app
Using default tag: latest
latest: Pulling from XXXXXXX/sample_app
Digest: sha256:f2e9fb6aaa96ffc4b03bcdeb526056c84abadf7dda38fa5bd34931533d8c4be8
Status: Image is up to date for XXXXXXX/sample_app:latest

では、以前使用したdocker-compose.ymlにimageを指定します。以下のような感じです。

version: '3'
  
services:
  web:
    container_name: application-container
    image: XXXXXXX/sample_app
    ports:
      - '5260:80'
    volumes:
      - ../:/var/www/project
    links:
      - kvs
  kvs:
    container_name: kvs-container
    image: memcached

ちなみにdocker_file関連を置いているディレクトリは以下のようになっています。

$ tree docker_files/
docker_files/
├── docker-compose.yml
└── web
    ├── Dockerfile
    └── vhosts.conf

では、以下のコマンドで変換してみます。

$ kompose convert
WARN Volume mount on the host "/path/to/projects" isn't supported - ignoring path on the host 
INFO Kubernetes file "web-service.yaml" created   
INFO Kubernetes file "kvs-deployment.yaml" created 
INFO Kubernetes file "web-deployment.yaml" created 
INFO Kubernetes file "web-claim0-persistentvolumeclaim.yaml" created 

$ tree
.
├── docker-compose.yml
├── kvs-deployment.yaml
├── web
│   ├── Dockerfile
│   └── vhosts.conf
├── web-claim0-persistentvolumeclaim.yaml
├── web-deployment.yaml
└── web-service.yaml

なにやらファイルがポコポコ作られました。

でもなんか warning出てます。

volumeのマウントはサポートされてない??

この指定でいけるのかな・・?

もう一回 convertしてみます。

$ kompose convert
INFO Kubernetes file "web-service.yaml" created   
INFO Kubernetes file "kvs-deployment.yaml" created 
INFO Kubernetes file "web-deployment.yaml" created 
INFO Kubernetes file "web-claim0-persistentvolumeclaim.yaml" created 

おお。Warning が消えた。

一個ファイル見てみます。

$ cat web-service.yaml 
apiVersion: v1
kind: Service
metadata:
  annotations:
    kompose.cmd: kompose convert --volumes=hostPath
    kompose.version: 1.12.0 ()
  creationTimestamp: null
  labels:
    io.kompose.service: web
  name: web
spec:
  ports:
  - name: "5260"
    port: 5260
    targetPort: 80
  selector:
    io.kompose.service: web
status:
  loadBalancer: {}

なにやら色々書いてますね。

ただ、Portとか webとか自分が設定した記述が入っているので、問題なく変換が実行されたのだと思います。

ではupで立ち上げてみます。

$ kompose up
WARN Volume mount on the host "/path/to/projects" isn't supported - ignoring path on the host 
INFO We are going to create Kubernetes Deployments, Services and PersistentVolumeClaims for your Dockerized application. If you need different kind of resources, use the 'kompose convert' and 'kubectl create -f' commands instead. 
 
INFO Deploying application in "default" namespace 
INFO Successfully created Service: web            
INFO Successfully created Deployment: kvs         
INFO Successfully created Deployment: web         
INFO Successfully created PersistentVolumeClaim: web-claim0 of size 100Mi. If your cluster has dynamic storage provisioning, you don't have to do anything. Otherwise you have to create PersistentVolume to make PVC work 

Your application has been deployed to Kubernetes. You can run 'kubectl get deployment,svc,pods,pvc' for details.

お?まだ warning出てるけどなんかいったっぽい?

ダッシュボードで確認してみます!

f:id:kojirooooocks:20180510070747p:plain

なんかきてるー!!

成功っぽいです。

でもこれどうやってアクセスればいいんだろう・・・

要調査ということで。。

とりあえずここまで。

docker-compose使ってローカル環境作った

こんばんは。

何番煎じだよって話だけど、勉強したので残しときます。

はじめに

今お世話になっている職場ではローカル開発環境がなく、サーバーにvhosts切って開発環境を作っています。

それはそれでいいのですが、新しい人(とくにデザイナーさん)が入ってきたときは、環境構築にすごく手間取っている印象でした(インフラ強い人がいないのが原因なのかも)

docker入れてコマンド一発ってとこまで持っていきたいので、入れてみました。

やってみた

↑の企業様の現在運用中のサービスは年代物で、だいぶ昔から蓄積されたデータがテストDBにも膨大に入っています。

かつ、昔に作られて、いらないっぽいけど呼び出されている、でも使われてない、みたいな意味不明のデータも大量にあるので、スキーマだけ持ってきてローカルにDB構築しても確実に動きません。

ということで、まず事前準備としてテストのRDSをパブリックアクセス許可にして、IP制限で接続できるようにしました。

あとは、httpd+php+memcacheというよくある構成です。

※ パスの設定はサービスに寄せてます。

まずdocker-compose.yml作成します。

version: '3'

services:
  web:
    container_name: application_container
    build: ./web
    ports:
      - '5260:80'
    volumes:
      - ../:/var/www/project
    links:
      - kvs
  kvs:
    container_name: kvs_container
    image: memcached

次にweb用のDockerfileを作成します。

FROM centos:centos7
MAINTAINER kojirock
RUN yum install -y http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
RUN yum -y update
RUN yum clean all
RUN yum install -y --enablerepo=remi-php56 httpd php php-mbstring php-pdo php-gd php-mysql php-xml php-intl php-pecl-memcached php-pecl-xdebug php-pecl-xhprof wget
RUN echo "ServerName localhost" >> /etc/httpd/conf/httpd.conf
RUN cp -p /usr/share/zoneinfo/Japan /etc/localtime
COPY vhosts.conf /etc/httpd/conf.d/
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]

virtualhostの設定ファイルも置いときます。

<VirtualHost *:80>
    DocumentRoot "/var/www/project/app/webroot"
    ErrorLog "/var/log/httpd/application_error.log"
    Options Indexes FollowSymLinks

    SetEnv ENVIRONMENT local

    <Directory "/var/www/project">
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

あとは、以下のコマンドでビルドして立ち上げるだけです。

$ docker-compose build && docker-compose up -d

f:id:kojirooooocks:20180506014035p:plain

出来ました。

あとは環境変数送ってるから、アプリケーション側でローカルの動きをするように設定ファイルを読み替えてあげれば完了です。

おわりに

docker本格的に触ったのって初めてでした。

まぁ本格的ってほどガッツリ触っていないですが・・・

laradockとかで作ったりはしてましたが、やっぱお手軽ツール触るだけでなく、キチンと触らないとダメですね。

あと、意外に便利だなと思ったのは、kitematicでした。

f:id:kojirooooocks:20180506014420p:plain

起動中のコンテナとかパット見で見れるのいいなと。

とりあえずRDS以外はローカル環境構築できたので、あとは使用中のテストDBの最適化を済ませてDBもローカルに持つようにしたいなと思います。

とりあえずこんな感じです。 dockerもっと勉強しよ。

お疲れ様でした。

cakephp3でfixtureデータを現状のDB情報で作成する

簡単ですが、なんとか週2postを達成するためにしょうもないネタを。

cakephp3でテストを作成する際にfixtureデータを作成するんですが、作るのが結構めんどくさい。

bakeコマンドでベースのファイルは作成できるけど、実際のデータは作らないといけない。

現状のデータをfixtureデータとして使えないかとみていると、オプションで使えることがわかった。

以下がコマンド

$ bin/cake bake fixture -r -n 30 -f -s テーブル名

これで指定したテーブルから、30件分の実データを引っ張ってきてfixtureデータとしてファイルを作成してくれる。

たとえばデータが死ぬほど多い場合は、以下のようにSQLでfixtureデータとして扱いたいデータを指定できる。

$ bin/cake bake fixture -r -n 30 -f  --conditions="created >= '2018-01-01 00:00:00'" -s テーブル名

一からプロジェクトを作る場合は問題ないけど、cakephp3への移植を行う場合は、一からテストデータ作るよりも、現状のデータを使ってテストを書くほうが早いと思った。

とりあえず少ないけどノルマ達成・・・w

Cakephp3のカスタムエラーページ作成

cakephp3ネタ続いてます。

今ガッツリやり始めてるので、気になったことはどんどん上げていく所存。

今回はエラーハンドリング。

公式見ればだいたい分かるけど、まとめとして書いときます。

Template/Error/error400.ctpとかerror500.ctpとか用意すればとりあえず表示されるけど、レイアウトも変えたいときは、独自のレンダラーを作成するっぽい。

1. config/app.php

<?php

...


    'Error' => [
        'errorLevel' => E_ALL,
        'exceptionRenderer' => 'App\Error\AppExceptionRenderer', ←ここを変更
        'skipLog' => [],
        'log' => true,
        'trace' => true,
    ],

2. App/Error/AppExceptionRenderer.php

<?php

namespace App\Error;

use Cake\Error\ExceptionRenderer;

class AppExceptionRenderer extends ExceptionRenderer
{
    /**
     * レイアウトを切り替える
     */
    public function render()
    {
        $this->controller->viewBuilder()->setLayout('error_layout');
        return parent::render();
    }
}

3. App/Template/Layout/error_layout.ctp

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <title>エラー!!</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
    <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
    <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" />
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
    <script type="text/javascript" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
  <main>
    <?php echo $this->fetch('content'); ?>
  </main>
</body>
</html>

4. App/Template/Error/error500.ctp

<div class="container">
    <div class="row">
        <div class="panel panel-danger">
            <div class="panel-heading">
                <h3 class="panel-title">Error!!!500</h3>
            </div>
            <div class="panel-body">
                <?php echo $message; ?>
            </div>
        </div>
    </div>
</div>

こんな感じで用意して、適当にエラー出してみる。

f:id:kojirooooocks:20180426010726p:plain

できた。

ちなみにerror500.ctpで表示しようとしている $messageAppExceptionRendererが継承している ExceptionRendererのrender()メソッド内で、catchしたExceptionの情報をtemplateに送ってくれているので、取れる。

f:id:kojirooooocks:20180426010737p:plain

↑みたいな感じで、色々セットしてくれている。

お客さんが使うような環境の場合は流石にエラーメッセージ見せるわけには行かないけど、管理画面の本番環境とかの場合は、xdebugとか起動させてない可能性があるから、こんな感じで穏当なエラーページ出して、エラー内容書いとけば、ササッと修正できそう。

ExceptionRendererが持っている$this->controllerは実行されているControllerになるので、それがPluginのControllerの場合は、テンプレートやレイアウトも各pluginのものになる。

pluginで環境を分けてる場合とかは地味に便利!

こんな感じでした。 おわり。

cake-pimple-di使ってみた。なかなか良かった。

cakephp3を引き続き触っております。

今回はCakePHPでもDI出来るよっていうcake-pimple-diを使ってみました。

pimple自体は結構触ってたのですが、cakeでも使えるってことなんで、ワクワクしながら触りました。

設定は以下みたいな感じです。

bootstrap.php

<?php

...

Plugin::load('RochaMarcelo/CakePimpleDi', ['bootstrap' => true, 'routes' => false]);

Pimple用設定ファイル

<?php

use Cake\ORM\TableRegistry;

return [
    'CakePimpleDi' => [
        'actionInjections' => [
            '\App\Controller\TestController' => [
                'index' => ['test_service'],
            ]
        ],
        'services' => [
            'test_service' => function() {
                return new App\Service\TestService(
                    TableRegistry::getTableLocator()->get(App\Model\Table\Tests::class)
                );
            },
        ]
    ]
];

TestController.php

<?php

namespace App\Controller;

use RochaMarcelo\CakePimpleDi\Di\InvokeActionTrait;
use App\Service\TestService;

/**
 * Class TestController
 * @package App\Controller
 */
class TestController extends AppController
{
    use InvokeActionTrait;

    /**
     * index page
     * @param TestService $service
     */
    public function index(TestService $service)
    {
        $service->hello();
        // -> hello!!
    }
}

TestService

<?php

namespace App\Service;

use App\Model\Table\Tests;

class TestService
{
    public function __construct(Tests $model)
    {
        $this->model = $model;
    }

    public function hello()
    {
        echo 'hello!!';
    }
}

caekphpって考えなしにプログラム作っていくと、コントローラにガリガリビジネスロジックが書き込まれていくので、ビジネスロジックはサービスクラスに逃したかったので、こんな構成にしました。

テストなんで、modelクラスもわたしてるんですが、問題なく使えます。

DIコンテナに登録されている別のserviceを呼びたい場合は以下

<?php

...

use RochaMarcelo\CakePimpleDi\Di\Di;
$service = Di::instance()->get('test_service');

簡単ですね。

キレイに設計できるし、テストもしやすそうだし、いいですね!