またどこかのCTOになってみた。
そう言えば、7月からジョインした会社でCTOになりました。
エンジニアは自分1人なんですけども。
孤独なエンジニアですが結構楽しくやっております。
来年の今頃は4〜5人エンジニアいたらいいなぁなどと期待しています。
アレもコレも作りたいのです。
エンジニアが増えても当然開発やります。
好きな業務はコーディング。
マネジメントなんてフィーリング。組織作りはノリとテンション。
雑談担当からお酒の相手まで幅広くカバー。
こんなCTOがいてもいいんじゃないかと思います。
あ、やる時はちゃんとやるんです、これでも。
いや、ホントに。
というわけなので、またブログタイトルを変えてみました。
内容は特に変わりませんが、宜しくお願い致します。
CakePHP3でunlockFieldとやらを使ってみた。
実はJavaScriptも嫌いです。
嫌いなものばかりなのにエンジニアとか言ってていいんでしょうか。
いいとか悪いとかではなく、ここまで来てしまうと言い続けるしかありません。
さて、本題。
なんですが、今回のネタは合っているのかどうかよくわかりません。
「何かよくわかんないけどできちゃったぞ」的なものなので、その辺りご了承ください。
やりたかったこと
hidden項目として設定したフィールドに対して、AjaxとかJavaScriptとかでごにょごにょした結果を格納してSubmitする。
結果
Securityコンポーネントから怒られた。
困りました。非常に困りました。
困ったのですが、そりゃデフォルトの値が書き換えられてるわけなので怒るのも当たり前です。
だってSecurityコンポーネントですもの。
でも、どうにかしたい。
よくある対応方法
対象のActionが実行された時にSecurityコンポーネントをOFFにすれば動きます。
なんですが、Submitするってことは何かしらの編集処理なわけなので、そのActionをまるっとOFFにするのって引っかかります。
それが正しい処理なのかもしれませんが、個人的にはちょっとアレです。
なのでSecurityコンポーネントをOFFにする書き方は書かないことにします。
気になる方はGoogle先生にお申し立てを。
今回やってみた対応方法
「書き換え対象のフィールドだけSecurityコンポーネント対象外にする」というやり方です。
ここでやっとunlockFieldが登場します。
公式にはこんな風に書いてあります。
unlockedFields
POST バリデーションを解除したいフォームフィールドの一覧をセットします。 このコンポーネントの他にも、 FormHelper::unlockField() でも解除できます。制限が解除されたフィールドは、POST 時に必須ではなくなり、 hidden フィールドの値もチェックされません。
ナニソレ、イミワカンナイ。
この説明で他の方々わかるんですかね。
自分にはさっぱり理解できませんでした。
理解できない時はとりあえず色々アレコレ書いて試すタイプなので、色々試しました。
「あー。もうできないからPOSTする時にモデルからもう一回取得すっかな」などと邪なことも考えながら。
結局こんな風になりました
unlockedFieldsとやらをセットするのはView側です。
こんなソースにしてみました。
<?php echo $this->Form->input('sample_id', ['type' => 'hidden']); ?> <?php echo $this->Form->unlockField('sample_id'); ?>
これだけです。
Ajaxで処理した時に上記ソースのsample_idに何か値がセットされます。
セットされてたら更新、されてなかったら新規登録みたいなことをやりたかったのです。
unlockFieldは何なんでしょうね。
無視しといて。よろしくみたいな感じなんでしょうか?
よくわかりません。
こんな書き方をすると、unlockFieldが有効になりSecurityコンポーネントさんも怒りません。
まぁとりあえずは結果オーライ、大勝利です。
合ってるのかなこれという不安は消えませんが、概ねいいでしょう。
正しい使い方を知ってる方いたら教えてください。
CakePHP3で画像データをDBに保存してみた。
その昔、こんな記事を書きました。
tsuralabo.hatenablog.com
画像データのDB登録記事がないことに1年近く経って気がつきました。
これはいけません。
ということで何事もなかったかの如く、記事を書くことにします。
DBへの画像登録というのは、いわゆるバイナリ登録です。
BLOBデータのアレですね。
昔から「BLOB」と聞くとスライム的な何かを想像してしまうのですが、それはどうでもいいです。
きっと過去にプレイしたRPGの何かなんじゃないかと思いますが、それもよくわかりません。
さて。
画像をDB登録する際はフォームヘルパーのFile属性に対して画像を指定して、それをアップロードするのが多いんじゃないかと。
それ以外もあるのかもしれませんが、自分が見たことないだけかもしれません。
とりあえず、View側の画像アップロード部分はこんな感じで作ります。
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12"> <span>画像</span> <div class="input-group"> <span class="input-group-addon"> <i class="glyphicon glyphicon-paperclip"></i> </span> <?php echo $this->Form->file('sample_image_id', [ 'class' => 'form-control', 'type' => 'file', 'div' => false, 'label'=> false ]); ?> </div> </div>
Bootstrap3使ってます。ちょっと怪しい書き方ですが、その辺は生暖かくお願いします。
さて、ここに指定された画像データがsubmitされた時、以下のようにごにょっとすると登録できます。
<?php /** * 画像登録処理(アップロードされた画像をそのまま登録) * @param type $imageFileModel image_filesテーブルのモデル * @param type $imageFile 登録する画像本体 */ public function saveImageFile($imageFileModel, $imageFile) { // 画像情報を取得 $imginfo = getimagesize($imageFile['tmp_name']); // ファイル拡張子に応じて処理 if ($imginfo[2] == IMAGETYPE_JPEG) { // JPEG画像データを生成 $createImage = imagecreatefromjpeg($imageFile['tmp_name']); } else if ($imginfo[2] == IMAGETYPE_PNG) { // PNG画像データを生成 $createImage = imagecreatefrompng($imageFile['tmp_name']); } // 画像データをバッファへバイナリ出力 ob_start(); imagepng($createImage); $imageBinary = ob_get_clean(); // モデル登録用パラメータ生成 $imgFileParam = [ 'content_type' => $imageFile['type'], 'image_data' => $imageBinary ]; // 新規登録用エンティティ生成 $entity = $imageFileModel->newEntity($imgFileParam); // 画像保存処理実行 $result = $imageFileModel->save($entity); // 画像メモリを解放 ImageDestroy($createImage); // データ登録時のIDを返す return $result->id; }
自分のよくやるパターンだと、上記のfunctionをコンポーネントに入れてます。
で、コントローラの方でそのコンポーネント経由でfunction呼び出してます。
「tmp_nameってなんだよ」ってのはview側からsubmitすればわかります。
「pr($this->request->getData());」とかやってみると出てくると思います。
トランザクションに関しては呼び元のコントローラの方でやっているのですが、環境や仕様に合わせて適宜修正して下さい。
一番最後にIDを返していますが、画像登録用テーブルと実テーブルが別ですのでIDを取得して実テーブルにパラメータセットしているためこんな感じになっています。ここも適宜修正して頂けますと。
getimagesize部分は対象画像のデータが色々取れますので、幅とか高さとかその辺の制限があればここで取得を。
でも登録処理する前にバリデーションは別でやりたいんだよ! という方は、上記functionの前にバリデーションを。
箇条書きっぽくなりましたが、以下を参考にして下さい。
<?php // $params['sample_image_id']でFile属性のデータが渡ってくることにします // 拡張子判定の場合 $extension = substr($params['sample_image_id'], strrpos($params['sample_image_id'], '.') + 1); // $extensionに拡張子が入るので判定。 // 判定用のリストを作っておくのもいいかもしれません private $extensionList = ['jpg', 'png']; if (!in_array($extension, $this->extensionList)) { $errorMessage[] = '画像の拡張子が不正です。jpgファイル、またはpngファイルを指定して下さい。'; } // サイズ判定の場合 $fileSize = $params['sample_image_id']['size']; // そもそもアップロードされてるかどうか判定 if ($params['sample_image_id']['error'] == 0) { // アップロードされた } else { // アップロードされてない // $params['sample_image_id']['error']が「4」とかだと思います }
こんな感じで画像データをDBにバイナリ登録したり、バリデーション実行したりするといいんじゃないかと思います。
でも、多分もっといい書き方あると思います。
まず動くことが大事。
動いてから色々ごにょごにょするといいかなと。
CakePHP3でリスト取得時のカラムを連結させてみた。
気がついたら8月が終わっていました。
あっという間に2017年もあと4ヶ月です。時間の流れの速さが恐ろしいです。
さておき。
ラジオボタンがあまり好きじゃなくてセレクトボックスの方が好きなタイプなのですが
CakePHP3だとこんな風にしてクエリを投げてView側にセットしています。
多分合ってます。
<?php // usersモデルを使うということにします $userModel = TableRegistry::get('Users'); $userList = $userModel->find('list'), [ 'keyField' => 'id', 'valueField' => 'user_name' ]) ->toArray(); // ViewにセットしてView側のセレクトボックスのoptionsにセット $this->set('userList', $userList);
インデントが様子おかしいかもしれませんが、こんな感じです。
リスト取得部分はモデルに書いた方がすっきりするかもしれません。
その辺はいつものアレですが好みです。
で。
上の例ですと「user_name」を画面上に表示するような雰囲気になりますが、例えばこれが苗字と名前に分かれていたとしたらセレクトボックスの方で連結させたいなーとなるんじゃないかと思います。
カラムだと何でしょう。family_nameとfirst_nameとかになるんですかね。
まぁその辺はどうでもいいですが、今回はそういうことにします。
文字列連結させたら終わり! と思っていたのですがやってみたら上手くいきませんでした。
いや、上手くいくかもしれませんが何だかできなかったのです。
仕方がないのでごにょごにょして実装したソースが以下です。
<?php // またusersモデルを使うということにします $userModel = TableRegistry::get('Users'); $userList = $userModel->find('list'), [ 'keyField' => 'id', 'valueField' => function ($entity) { // この部分をEntityから取得する // 変数は$enitityじゃなくて構いません。適当に return $entity->user_full_name; } ]) ->toArray(); // ViewにセットしてView側のセレクトボックスのoptionsにセット $this->set('userList', $userList);
<?php // usersモデルのEntity側(Model/Entity/User.php) protected function _getUserFullName() { // Entity側で苗字と名前を連結させて返す return $this->_properties['family_name'].$this->_properties['first_name']; }
のような感じで書くとキレイにカラムが連結された状態でセレクトボックスにセットされます。
functionとかなんなの。イミワカンナイという方は、以下のような書き方でもいけます。
<?php // これもusersモデルを使うということにします $userModel = TableRegistry::get('Users'); $userList = $userModel->find('list'), [ 'keyField' => 'id', 'valueField' => function ($entity) { return $entity['family_name'].$entity['first_name']; } ]) ->toArray(); // ViewにセットしてView側のセレクトボックスのoptionsにセット $this->set('userList', $userList);
ちなみに自分はイミワカンナイ派です。
お好きな方を使うといいんじゃないかなと思います。
ConoHaのLAMPイメージでサーバ構築してみた 〜Composerインストール〜
GitLabサーバが構築できた。
LAMPイメージから作ったサーバのPHPバージョンアップができた。
LAMPイメージから作ったサーバのMariaDBバージョンアップができた。
もうこれ、インフラもできるんじゃないですかね?
すっごーいとか言っていたら、きっと本職の方に石を投げられてしまいます。
さて、CakePHP3を使うので「あ。Composerもいるんじゃないの?」と気がつきました。
まぁ当然のごとく、インストールされていません。
仕方がないのでインストールします。
Composerのインストール
非常に簡単です。
公式ページを見て、その通りにコマンドを打てば終わりです。
上記のページを開くとインストールする時のコマンドが記載されています。
この4つのコマンド(2017年7月現在)を、上から順番に実行するだけです。
インストールする時は /usr/local/src/ 辺りに移動した方がいいかもしれません。
composer.pharを移動する
インストールが終わったら「composer.phar」を移動させましょう。
移動するのはパスを通すためです。
mv composer.phar /usr/local/bin/composer
ConoHaのLAMPイメージでサーバ構築してみた 〜MariaDBアップデート〜
前回はPHP5.6からPHP7にアップデートしました。
いい気になって、MariaDBのアップデートもしてみることにします。
どうでもいいんですが、自分は調子に乗りやすいB型です。
MariaDBの最新レポジトリを確認する
構築したLinuxのOSに応じてレポジトリが異なりますので、以下から確認します。
MariaDB - Setting up MariaDB Repositories - MariaDB
自分の場合はCentOS7なので、画面上からポチポチ選択しました。
1.Choose a Distro → LinuxのOS選択
2.Choose a Release → Linuxのバージョン選択
3.Choose a Version → インストールするMariaDBのバージョン選択
上記3つを選択すると、画面上に「yumでアップデートする時はこれ使ってね」的なものが表示されます。
自分の場合だと、以下のような記載でした。
Here is your custom MariaDB YUM repository entry for CentOS. Copy and paste it into a file under /etc/yum.repos.d/ (we suggest naming the file MariaDB.repo or something similar).
英語はよくわかりませんが、「/etc/yum.repos.d/にMariaDB.repoってファイル作ってね」ぽいです。
MariaDB.repoを作成して画面の内容を貼り付ける
ただ作るだけです。
vim /etc/yum.repos.d/MariaDB.repo
貼り付ける内容は前項で表示されている内容です。
こんな感じかと思います(CentOS7の64bit + MariaDB10.2の場合)
# MariaDB 10.2 CentOS repository list - created 2017-07-09 10:57 UTC # http://downloads.mariadb.org/mariadb/repositories/ [mariadb] name = MariaDB baseurl = http://yum.mariadb.org/10.2/centos7-amd64 gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB gpgcheck=1
よくわかりませんが、そのまま貼っておきました。
MariaDBを一旦停止する
そりゃアップデートするわけですから、止めるのも納得です。
以下のコマンドでMariaDBを停止できますので、停止してしまいましょう。
systemctl stop mariadb.service
多分止まってます。
エラーが出ていなければ。
ConoHaのLAMPイメージでサーバ構築してみた 〜PHP7にアップデート〜
一人でGitLabサーバ構築ができました。
これは、インフラもできるエンジニアとしての大きな一歩を踏み出したと言っても過言ではありません。
「インフラですか? まぁ多少は。フフ」ぐらい言ってもいいかもしれません。
絶対言いませんけども。
さて、次は社内システムとしてのWebアプリを作ることにしました。
スケジュール閲覧とか問い合わせ管理とかそういうのです。
Webアプリ自体はサラっとCakePHP3で作ったのですが、今度はこれをサーバに載せなければいけません。
またです。またサーバを構築です。
やりたいこと
URLを知っていればアクセスできる。
ログインするためのIDとパスワードが必要。
スマホでアクセスできる。
DBは同じサーバ上にあればOK。
LAMP環境ですね。
ConoHaさまにお伺いを立てたところ、LAMPイメージがありました。
またも大勝利が見えています。
出来上がったLAMPイメージを確認してみる
なんですが。
PHPのバージョンが5.6でした。
「あれ、LAMPイメージ作る時に設定いるのかな?」と思っていたのですが、そうではなさそうでした。
どうやらConoHaのLAMPイメージで出来たサーバは、PHP5.6のようです。
PHP7使いたいんだけどなーと不安になりながらググってみたら、どうやら自分でインストールする必要がありそうです。
自分にはそんなことはできません。何でConoHaさまはPHP5.6なんだよ!
と文句をつけても仕方がありませんので、腹をくくってPHP7を入れてみることにしました。
もうこの時点で不安です。
yumをアップデートする
「ヤム」とか読むらしいです。
Linuxのパッケージ管理ソフトです。流石にこれぐらいは知ってます。
まぁアップデートとか言われるとガタガタ震えてしまうのですが。
グーグル先生にお申し立てをして、以下の手順でyumをアップデートしました。
# yumのお掃除コマンドらしいです。 yum clean all # yumのアップデート(-yのオプション入れてもOKです) yum update # 何か知りませんがやった方がいいらしいので yum -y install yum-plugin-priorities
雑ですみません。
とりあえず上記手順でyumのアップデートが出来たようです。
デフォルトのPHPを削除
ConoHaのLAMPイメージにデフォルトでインストールされていたPHPを削除します。
要するに「PHPが稼働しないLAMP環境」になります。
ちょっとどころか相当不安だったのですが「ダメだったら作り直せばいいか!」的なノリで削除してやりました。
以下、削除手順です。
# 初期インストールされているPHPのファイルを確認(リスト表示されます) rpm -qa | grep php # PHP関連のファイルを削除 yum remove php5*
本当に削除されてしまいました。
PHP7をインストール
お利口なyumがインストールしてくれます。
何も考えずに以下のコマンドを実行しました。
yum --enablerepo=remi-php70 -y install php php-mbstring php-pear php-fpm php-pdo php-intl php-mysqlnd php-pecl-redis php-xml php-gd php-json
何かよく見ると「php-intl」とかCakePHP3インストールに必要なライブラリも入ってます。
多分大丈夫でしょう。
インストールできたはずのPHPバージョン確認
さて、多分ちゃんとPHP7がインストールされているはずです。
ドキドキしながらPHPのバージョン確認です。
php -v PHP 7.0.21 (cli) (built: Jul 5 2017 14:33:41) ( NTS ) Copyright (c) 1997-2017 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
!!!
PHP7になっていました。
これは大勝利と言っていいでしょう。
というわけで、PHP7が無事にインストールできました。
怪しげなインフラエンジニアスキルが助長されていきます。