プログラミング

ブログを開設しました

ゆとりは再びブログを開設しました。みなさまよろしくお願いいたします。

こんにちは。ゆとりです。

みなさま、初めまして。ゆとりです。

↑写真は、いつかの帰り道。あまりに空が綺麗だったので、そのおすそ分けです。

 

もしかしてお久しぶりの人もいるかもしれません。

3〜4年前、同じ「ゆとり社員は考える」というタイトルで、ブログをやっていました。

当時右も左もわからない状態で、使用したCMSはWordPress。

今回は、baserCMSを使用しました。

現在仕事で死ぬほど使っているのがbaserCMS。

WordPressに比べてかゆいところに手が届くし、カスタマイズもしやすいです。

 

テーマについては、自分でHTMLテンプレから作って組込して、

独創的でかっこいいもの作りたい・・・!

と思っちゃいたのですが、やっぱデザインって難しい。

というわけで、マーケットで無料で取得できる「ratio_3_2」を使用しました。

まあ、ゆくゆくはデザインの細かい部分をカスタマイズしたり、

自作のものとテーマを差し替えたり、そんなこともしてみたいですね〜

いずれ・・・

自己紹介

  • 住み・・・福岡
  • 職業・・・Webプログラマ
  • 言語・・・PHP、java、C#、C
  • フレームワーク・・・CakePHP、Laravel、WPF
  • 興味・・・ブログ運営、アプリ開発(金になることがしたい〜〜〜)

こんなとこですね。

都度更新します。

今後とも、何卒よろしくお願いいたします!!!!!

≫ Read More

ゆとりについて 2019/10/26morishi

ブラウザ遷移なしでHTMLの更新をしたい・・・Ajax非同期処理をやってみました

クリック動作等でHTMLの一部を更新したい・・・。
しかし画面遷移やブラウザの更新が走っちゃうのはやだなあ・・・。
そんな時にAjax非同期処理。
ゆとりの初体験のコードサンプルです。

つい最近、「Ajaxを利用してjsonを取得し、画面上に内容を表示する」
という実装をおこないました。

・HTMLの1部分のみをクリック等のアクションで変更させたい・・・
画面遷移するのはやだ・・・
という要望を持った人向けです。

ゆとり自身、バックエンドの開発経験はあるものの、
HTMLだのjavascriptだのjQueryだのは初めてなので、
手探りで進めていきます。

まずAjaxとはなんぞや

下記のQiita記事がわかりやすいです。

つまり、サーバーからのレスポンスと、
クライアントでの動きが同期しない処理→非同期処理ってことですね。(まんま)
サーバーの処理で画面全体の更新が走らないっていうのはいいもんですね。

利点として、
・サーバーからのレスポンスを待ってクライアント側の停止が起こらないこと
 (最近は割と停止時間も減りましたけどね)
・画面がリフレッシュしないため、現在のブラウザの状態がちゃんと残ること(スクロールの位置、入力内容等)
が大きいと思います。

サンプル画面つくってみた

こんな感じに作成しました。

説明を箇条書きにて。


・初期画面では、[画像][タイトル][URL] が2セット、以下の内容で2件表示されている
    画像:いつも使ってるこれ
    タイトル:初期サンプル1、2
    URL:https://example.com/
・下の[1][2][3]をクリックすると、Google Books APIs より
 「阿刀田高」の書籍情報を検索し、2件表示する
    画像:書籍サムネイル画像
    タイトル:書籍タイトル
    URL:Google Play書籍購入画面のURL
・書籍の検索条件についてはキーワード以外なし。適当。
    [1]をクリックすると検索結果の20ブロック目表示
    [2]をクリックすると検索結果の30ブロック目表示
    [3]をクリックすると検索結果の40ブロック目表示

ソースはこんな感じ

See the Pen KKKYNYQ by ゆとり社員は考える (@shineyutori) on CodePen.

処理の流れ・・・

HTML:
■ulタグ(class : hoge-link)内のaタグクリック時にイベントが発火します。
 →void(0) でリンクは無効化済みです。

jQueryのイベント内処理:
■json取得用URLを作成します。
 ・クリックしたaタグのdata-idが、json取得のstartIndexパラメータに設定されます。
  json取得用URLはこちら
  https://www.googleapis.com/books/v1/volumes?q=阿刀田高&maxResults=2&startIndex={data-idの値}

■Ajax内で、jsonの取得・データの取り出し・HTMLの書き換え処理が実行されます。
 ・URLでjsonを取得し、取得したデータを配列に格納
 ・hogehogeクラスのHTML要素内のエレメントを空白にする
 ・配列をeachでループさせ、その中で各要素に値をセット
    > htmltextという空白の変数を設定し、テキスト形式で値を設定したHTML要素を文字列で追加
    > 設定後、hogehogeクラスのHTML要素内に、htmltextに文字列で設定したHTML要素を追加

→→hogehogeクラス内のHTML初期表示が削除され、
  jsonより作成したHTMLに書き換えられている!

・・・意外と簡単でした。

感想

今回、JavaScript自体初めて書いたので、手探り手探りでした。
なので、「とりあえず動かしたい!」という思いでとにかく手を動かしていたので、
ブログに残そうといろいろ推敲しているうちに修正点がボロボロ出てきて、
結局記事を書くのに丸1日かかってしまいました・・・。
それにしても、jQueryもAjaxもJavaScriptも書き始めるとめちゃくちゃ楽しいですね!
なんで今まで全然書いてなかったんだろう・・・
これからもたくさん書いていこうっと・・・

≫ Read More

HTML/CSS/JavaScript 2019/11/22morishi

CakePHPが学びたい・・・「初心者」状態〜「それなりに使える」状態に移行するための解説サイトを紹介

CakePHPを学びたい・・・でもわからない状態から挫折する人って多いみたいですね。

そんな方々のために、読んで写経するといいよ的なサイトを紹介します!

誰しもが「初心者」という経験をします。
そして、「勉強中」を通じ、「よくわかる」「開発できるの域に到達する者、
「挫折する」「浅くしか理解できない」に落ち着いてしまう方もいます。

ゆとりはと言うと、正直に言うと現状こんな感じ。

  1. Model、View、Controllerを使用する「MVCモデル(CakePHPで採用されているモデルです)」については漠然と理解できるし、それなりに使える
  2. 上記の概念については、細かく説明できるほどにない
  3. イベント処理やビヘイビア等については弱いが、ネットで検索して情報収集すればそれなりにできる

なんとか2)3)を克服すべく、奮闘中です。
しかし、機能開発等についてはそれなりにできるようになってきました。
多分、「全くの初心者」状態「それなりに理解はできる」状態への移行という部分の行き詰まり部分は越えたはず。
ここで、多くの人は脱落するみたいですね。これを第一段階と呼ぶことにします。
しかし、ゆとりはそれ以降の部分で若干行き詰まっているのを感じます。
「なんとなく理解してて、それなりに開発できる」状態「ちゃんと理解してて、自分で考えながら開発できる」状態への移行です。
ここを第二段階と呼ぶことにします。
ここの第二段階でスランプを迎える人も多いそうです。(体感・周りのベテランさんたち曰く)
ゆとりは、「第二段階ではこんなサイト・本・学校で勉強するといいよ!」みたいなアドバイスはできませんが(むしろ教えて欲しいです)
「第一段階で行き詰まっている人はこれをみるといいよ!」みたいなサイトならいくつか紹介することができます。
というわけで、以下ご確認ください!!!

関連記事はこちら

とりあえずデータの登録・編集・一覧表示・削除等、ログイン処理等ができるような手順が初心者にわかりやすく書かれたサイト

web初心者がcakephp3を導入からやってみた - Qiita

CakePHP3の環境作りを丁寧に解説したページ。割と公式周りでは省略されがちな部分。
PHPでの実装自体初めて・・・みたいな方にもオススメ。

CakePHP3でWebアプリ開発 - Qiita
CakePHPのインストール〜認証機能(ログイン)の実装〜顧客情報の登録・閲覧・編集機能の実装〜注文登録機能の実装までを解説したページです。
勘のいい方なら、写経するだけで大体わかるはず。

CakePHPならではの機能を解説したサイト

【cakePHP】配列を組み替える便利なHashクラス | ぼくの答えはいつもNo…そしてYes!

CakePHPでは、Hashという便利なクラスを利用できます。
Hashとは、配列の組み替え、検索、データの抜き出し等が簡単な記述でできるとても便利なクラスです。
(これで、配列からデータを取り出すのに、foreachを回したりしなくていい!!!!素晴らしい!!!!)
しかし、Hashの関数についてはど忘れがちなので、毎回上記サイトを参考にしています。

つまずきがちなイベントを解説

CakePHP3でイベントリスナーを用いた処理の実装(&メールやSlackでの通知)

MVC(モデル、ビュー、コントローラ)については割と解説さいとが多いですが、イベント系の機能についての解説はちょっと少ない印象。
イベントの実装をマスターするとできることがめちゃくちゃ増えるので、こちらは読んでおくとGood。
ゆとりも今めちゃくちゃ一生懸命読んでます。

まとめ

実際、初心者状態のゆとりは上記サイトで学びました。
しかし、実際に対面でアドバイスを受けたり業務で読んだコードから学んだり・・・といった経験もあるので、
上記サイトだけで網羅できているかは保証できません。
サイトを一生懸命読む作業も意味はあると思いますが、
一番大事なのは、実際に手を動かすこと・実際のコードを読んでいろいろパクること(GitHubにたくさん落ちてますね!)だと思います。
上記で紹介したサイトが、少しでも多くの「CakePHP挫折者」を減らす手伝いができると嬉しいです。

≫ Read More

CakePHP 2019/12/23morishi

CakePHP4をローカルにインストールしてみたよ

CakePHP4系が、昨年12月に正式リリースされていたようです。さっそく触って、素人なりに主に初期TOPページ周りについてごちゃごちゃ抜かしてみます。

CakePHP Community Managerのミーガン様よりメルマガ来てました。
昨年12月にCakePHP4の正式リリースをしたよ、と。
早速触ってみました。
composerでまた詰まってしまったのは内緒。
関連記事はこちら

インストールしてみました。初期TOP画面はこちら

ホイ!!!!!!
なんか色が淡くなってなかなかナウですね。2系、3系の初期TOPは今見ると若干くどく感じます。

過去バージョン(2系、3系)初期画面TOPとの比較

うん、やっぱり今2系、3系を見ると若干古臭く感じますね。
とくに2系は、iOS7以降のデザインに慣れたあと、iOS6以前のデザインを見た時と同じ感覚。
やはり今はフラットな感じが主流なのですね
3系はまだそこまで古くは感じないですが、
今見ると赤の主張が激しい気がするし、4系のフラットながらも立体感もあるデザインを見た後だとやはり物足りなく感じてしまう。

大きく変わったところ

パッと気づいた大きな変更点はこちら。

PHP7.2以上必須となった
・テンプレートファイルの拡張子が.ctp→.phpになった
・デフォルトレイアウトがシャレオツ(Milligramというめちゃくちゃ軽いCSSフレームワークになったそうです)

その他、変更点が軽くまとめてあるサイト見つけたので貼ってみます。

まとめ

これで何を作ろうかな〜
とりあえず、2.X系で途中まで作成しているものを移植してみようと思います。
2系に慣れているので、テーブル挿入がうまく動かない。
3系に慣れておけばよかった・・・。
うまくいったあたりでまた記事書きます。

≫ Read More

CakePHP 2020/01/19morishi

baserCMSのプラグインを作成しました。ユーザー情報をCSVインポートにて一括登録できるプラグインです

baserCMS利用者向けに、プラグインを作成・マーケットに出品しました。ユーザー情報を一括登録できるプラグインです。紹介・使用手順の説明・今後追加したい機能について書いていきます。

baserCMS利用者向けに、プラグインを作成・マーケットに出品しました。ユーザー情報を一括登録できるプラグインです。

作成したプラグインはこちら

今回作成したのはこちらのプラグイン。

現在できることは、

「複数人のユーザー情報をまとめたCSVを作成・インポートすることで、一括でbaserCMSのユーザー登録ができる」

ただ、それだけ。

それだけなんですが、案外需要あるのではないかと思いまして。
ゆとりはほしかったです。

職場の仕事の中で、
ユーザーグループ50程度・ユーザーを100人程度登録する機会がありました。
そのときは、さすがに100人を管理画面から手動で登録する気力もなく、
ユーザー情報を一括で登録するプログラムを書きました。
結果、開発・動作確認・テスト・実際に登録・・・と手順を踏んでいくと、
結局手動のほうが早いじゃん・・・みたいな結果になりました。
(まあ、手作業でやっていくとケアレスミスも比較的発生しやすいと思うので、やっぱり手間がかかっても一括でやるべきなんでしょうが・・・)

あと、baserCMSのフォーラムにて、
「一括で万単位のユーザを削除・登録させる方法はありますか?」みたいな質問もありました。
意外とこういう機能って求められてるんじゃないかな〜って思いました。

使用手順はこちら

たとえばこんなユーザー情報を登録したい場合
プラグインに同袍されている、
「user_import.csv」を編集します。(テキストエディタや表計算ソフト等で編集できます)

1行目が見出しで、2行目はサンプル(例)となっております。
2行目に倣って、3行目以降にユーザー情報を追記していきます。
2行目のサンプルに関しては、編集後必ず削除してください。
(2行目以降を取り込む仕様としているため、削除しないとサンプルのユーザー情報も作成されてしまいます)

「グループID」部分に入れる数字ですが、
所属させたいユーザーグループのNOを記入します。


ユーザーグループのNOは、

{サイトURL}/admin/user_groups/ にアクセスするとわかります。
図で示している部分です。

たとえばユーザーグループ「システム管理(admins)」にユーザーを所属させたい場合、
「グループID」「1」です。

CSV作成できましたかね?
ではインポートします。

{サイトURL}/admin/user_import/user_imports/ にアクセスし、
作成したCSVを選択後「インポート」ボタンを押してください。
ファイル内容に問題がなければユーザーが正常に追加されます。

今後追加したい機能

  • まだユーザー追加しかできないので、ユーザーの編集・削除・ユーザー情報エクスポートもできるようにしたい
  • エラーログを見やすくしたい
  • ユーザーグループも扱いやすくしたい

まだユーザー追加しかできないので、ユーザーの編集・削除・ユーザー情報エクスポートもできるようにしたい

追加のみで編集も削除もエクスポートもできないとなにかと不便です。なるべく早く対応します。

エラーログを見やすくしたい

現状、インポートの際にエラーがある場合、
app/tmp/logs/log_user_import.log にログが出力されるようになっています。
ただ、配列形式のまま出力しているだけ・・・みたいな感じで初見だとよくわからないと思うので、
見やすい形式に改修したいです。

ユーザーグループも扱いやすくしたい

別機能になってしまうとは思うのですが・・・
ユーザーグループも簡単に扱えるようにしたいですね。
ユーザーグループ登録編集は別に使いづらくはないのですが、
ユーザーグループに対してアクセス制限を設定するときが一番めんどくさいですね・・・
なんとか、設定がしやすくなるアイデアを考えている最中です。

まとめ

はじめてプラグインを公開しました。
今まで仕事にて案件専用のプラグインは作成していたのですが、
マーケットに出したのは初めてです。
皆様の反応が気になります・・・。

また、近々このプラグインの改修や、他のプラグインの作成という形でマーケットに貢献できればと思います。
今回は無料プラグインとして出品しましたが、
次は500円くらいで売れるもの作りたいなあああ

≫ Read More

baserCMS 2020/07/08morishi

PHP7技術者認定[初級]試験を受けました

勉強の過程で初めて知ったPHP7の知識を中心にまとめていきます

2020/08/29(土)に、PHP7技術者認定[初級]試験を受験しました。
勉強時間は4時間ほどです。
勉強するにあたって、本はこちらを利用。
試験結果はこんな感じ。

試験本番の内容は意外と難しく、終了直後は「落ちた?」と思いましたが、
割と余裕で合格。

今回、試験勉強をしていて「へぇ〜」となった問題を4題セレクトしてみました。
(著作権のため、自分なりに問題を改変しております。)

宇宙船演算子

問題1:下記の実行結果を選択しなさい。
  
    print(1 <=> 2);
    print(3 <=> -2);
    print(2 <=> 2);
  

A:001 B:1-10 C:-110 D:実行エラー

宇宙船演算子( <=> )の問題です。

宇宙船演算子とは、左の値と右の値を比較して左辺が大きい場合は「1」、同じ場合は「0」、右辺が大きい場合は「-1」を返す演算子です。
PHP7より追加された演算子です。

  
    print(1 <=> 2);   // 右の方が大きいので「-1」

    print(3 <=> -2);  // 左の方が大きいので「1」

    print(2 <=> 2);   // 同じ大きさなので「0」
  

よって、正解は「C:-110」です。

変数名の命名規則

問題2:変数名の指定として誤ってるものは?(2つ選択)

A:YUTORI B:4yutori C:Yutori_Shine D:_yutori E:yutori-shine F:yutori2020

変数名の命名規則の問題です。下記の規則のもと、変数を命名できます

  • 頭に使って良いのはアルファベットとアンダースコア
  • 2文字以降に使える文字はアルファベット、数字、アンダースコア

よって、正解は「B:4yutori、E:yutori-shine」です。

等価演算子

問題3:次のコードの実行結果は?
  
    $data = '2020';

    if ($data == 2020) {
        print 'OK';
    } else {
        print 'NG';
    }
  

A:「OK」が表示される B:「NG」が表示される C:なにも表示されない D:実行エラー

等価演算子の問題です。

よく条件判定に使用する「 == 」「 != 」「 <> 」は、実は型まで比較しません。型まで完全一致しているかの比較をおこないたい場合、

「 === 」「 !== 」を使用する必要があります。

 

演算子 記述例 意味
== a == b bとaの値が等しい
=== a === b bとaの値が等しく型も等しい
!= a != b bとaの値が等しくない
<> a <> b bとaの値が等しくない
!== a !== b bとaの値または型が等しくない

よって、正解は「A:「OK」が表示される」です。

ファイルの読み込みエラー判定

問題4:ファイルの読み込みエラーを判定する場合、「???????」に入れるべき条件文は?
  
    $file = file_get_contents('hoge.txt');

    if(???????) {
        print 'ファイルの読み取りに失敗しました';
    }
  
A.    if ( $file )
B.    if ( !$file )
C.    if ( !$file == false )
D.    if ( !$file === false )

ファイルの読み取りエラー判定の問題です。

「0」とだけ書かれたファイルを読み込んだ場合、$fileには文字列「0」が返される。 PHPでは「0」はfalseと返されるため、AやCはfalseと判定されてしまう。 同値演算子「===」を用いることで、 返り値がboolean型のfalseであることを判定できる。

よって、正解は「D:if ( !$file === false )」です。

まとめ

今回は、試験に向けて勉強してて「へぇ〜知らなかった」ということをまとめてみました。
試験合格自体はほぼノー勉でいけましたが、今回いろいろ知れて有益だったので、
勉強してよかったです。
気軽に達成感を得られますし、割とウケのいい資格なので皆さんもぜひ受験してみてくださいね!

≫ Read More

PHP 2020/08/30morishi

「シカクパーク〜みんなの資格体験記〜」をリリースしました!

資格の受検体験記投稿サイト「シカクパーク〜みんなの資格体験記〜」をリリースしました!これから頑張って育てていきますので、ご愛顧よろしくお願いいたします!!!

こちらが、リリースした「シカクパーク〜みんなの受検体験記〜」です!!!
サービス詳細や今後の展望について紹介していきます!

サイトコンセプト

資格を受検した方々の投稿を集めて、
学習方法・受検しての感想等を共有できるサイトです。
今後資格を受検する方々の学習・資格を受検した方の振り返り の手助けになるサイトを目指しています。

投稿はこちらから

こちらから投稿できます。

現在、「情報処理技術者試験」の下記資格について投稿可能です。

 

  • ITパスポート
  • 基本情報技術者
  • 応用情報技術者
  • ITストラテジスト
  • システムアーキテクト
  • プロジェクトマネージャ
  • ネットワークスペシャリスト
  • データベーススペシャリスト
  • エンベデッドシステムスペシャリスト
  • 情報セキュリティスペシャリスト
  • 情報セキュリティマネジメント
  • ITサービスマネージャ
  • システム監査技術者

今後の展望

資格コンテンツ追加

直近の追加予定の資格コンテンツはこちらです。
  • Linux技術者認定資格「LinuC」(2021年2月予定)
  • Microsoft Office スペシャリスト MOS(2021年3月予定)
  • CAPM®試験(2021年4月予定)

マイページ機能追加

マイページ機能を追加予定です。
ユーザー登録・ログインした上で体験記を投稿した場合、後にマイページより投稿の編集・削除が可能となります。
また、ユーザーごとの体験記閲覧が可能となります。
他にもお気に入り機能・ユーザーのポートフォリオ機能等、いろいろ検討中です。

まとめ

割とシンプルな投稿サイトを構築していたつもりなのですが、
データの保存や表示、サイトのユーザビリティ等を考えれば考えるほどいろいろタスクが湧き出し、
リリースまで3ヶ月以上かかってしまいました。
(しかも、まだ課題は山積みです)
今後、月ごとにいろいろとアップデートしていく予定なので、よろしければご活用をお願いいたします!

≫ Read More

 2021/01/11morishi

CakePHP4で、フォロー機能のアソシエーションを実装してみた(Ruby on Railsの記事を参考に)

CakePHP4にて、フォロー機能を実装しようとしたのですが、なかなかうまくいきませんでした。困っていたものの、
Ruby on Railsにて実装している記事を参考にやってみたらうまくいきましたので共有します。

CakePHP4にて、フォロー機能を実装しようとしたのですが、なかなかうまくいきませんでした。困っていたものの、 Ruby on Railsにて実装している記事を参考にやってみたらうまくいきましたので共有します。
参考にした記事はこちら。
順番に紹介していきます!

やりたいこと

・Membersモデルを作成し、Member同士のフォロー機能のアソシエーションを作成する
・Membersのfindで、該当Memberのフォロー中Members・フォロワーMembersを取得し、それぞれのMemberデータ(名前等カラム情報)も取得する(containで取得できるようにする)
今回作成したMemberのテーブル例
  
CREATE TABLE `members` (
  `id` int(8) NOT NULL,
  `email` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `created` datetime DEFAULT NULL,
  `modified` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `members`
  ADD PRIMARY KEY (`id`);

INSERT INTO `members` (`id`, `email`, `name`, `created`, `modified`) VALUES
(1, 'test1@example.com', 'メンバー1', '2020-12-15 05:50:28', '2020-12-15 05:50:28'),
(2, 'test2@example.com', 'メンバー2', '2020-12-15 05:50:28', '2020-12-15 05:50:28'),
(3, 'test3@example.com', 'メンバー3', '2020-12-15 05:50:28', '2020-12-15 05:50:28'),
(4, 'test4@example.com', 'メンバー4', '2021-01-13 11:22:26', '2021-01-13 11:22:26');
  

今回の例ですと、

「メンバー1」が「メンバー2」「メンバー3」をフォローして、
「メンバー3」「メンバー4」が「メンバー1」をフォローしている場合

「メンバー1」のフォロー一覧取得で「メンバー2」「メンバー3」のメンバー情報、
「メンバー1」のフォロワーー一覧取得で「メンバー3」「メンバー4」のメンバー情報 を取得したいのです。

CakePHP4にて、フォロー機能を実装する手順①中間テーブルを作成する

フォロー機能のアソシエーションは、多対多(members対members)のアソシエーションとなっています。
今回は、中間テーブル「follows」を用意して「一対多」(member対follows)のアソシエーションを作成します。

中間テーブルを作成し、bakeにてモデルを作成します。

  
CREATE TABLE `follows` (
  `id` int(8) NOT NULL,
  --フォローする側
  `following_id` int(8) NOT NULL,
  --フォローされる側   
  `follower_id` int(8) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `follows` (`id`, `following_id`, `follower_id`) VALUES
(1, 1, 2),
(2, 1, 3),
(3, 3, 1),
(3, 4, 1);
  

CakePHP4にて、フォロー機能を実装する手順②モデルを2つに分けて考える

①フォローする側の目線
②フォローされる側の目線
に分けて考えていきます。

順序として、下記のように実装していきます。
1)Followsモデルを2つに分けて考える
2)Membersモデルを2つに分けて考える

1)Followモデルを2つに分けて考える

・ActiveFollowings (フォローする側の目線)
・PassiveFollowings (フォローされる側の目線)

Memberモデルに、hasMany()メソッドを追加します。

/src/Model/Table/MembersTable.php
  
        $this->hasMany('ActiveFollowings', [
            'className' => 'Follows',
            'foreignKey' => 'following_id',
        ]);

        $this->hasMany('PassiveFollowings', [
            'className' => 'Follows',
            'foreignKey' => 'follower_id',
        ]);
  

1つのFollowモデルを仮想の2つのモデルに分けています。
なので、実際のFollowsモデルであることをclassNameプロパティにて定義します。

フォローをする側の目線では、フォローする側(following_id)を元にフォローされる側(follower_id)を引っ張ってくるので、foreignKey(外部キー)をfollowing_idに指定する必要があります。
逆に、フォローされる側の目線では、フォローされる側(follower_id)を元にフォローする側(following_id)を引っ張ってくるので、foreignKey(外部キー)をfollower_idに指定する必要があります。

2)Memberモデルを2つに分けて考える
・ Followings (フォローする側の目線)
・ Followers (フォローされる側の目線)
/src/Model/Table/FollowsTable.php
  
        $this->belongsTo('Followings', [
            'className' => 'Members',
            'foreignKey' => 'follower_id',
        ]);

        $this->belongsTo('Followers', [
            'className' => 'Members',
            'foreignKey' => 'following_id',
        ]);
  
Followモデルと同様にあくまでも、1つのMemberモデルをそれぞれ名前を付けて2つのモデルに分けたという仮想モデルであるため、本当はMembersモデルであることをclassNameで記載する必要があります。

CakePHP4にて、フォロー機能を実装する手順③フォローする側の目線で考える

1行目:Followsモデル(ここではフォローする側目線なのでActiveFollowings)について記述
上記の「CakePHP4にて、フォロー機能を実装する手順②モデルを2つに分けて考える」ところで説明済み。
2行目:ActiveFollowingsを介してフォローされた人を集める
ActiveFollowingsを通ってフォローされた人を集める。フォローされた人を集めるには、"Followers"モデルを参照することになるため、propertyName:Followersを記述する。
この一連の流れを"Followings"と命名したのでhasMany('Followings')と記述する。
/src/Model/Table/MembersTable.php
  
        $this->hasMany('ActiveFollowings', [
            'className' => 'Follows',
            'foreignKey' => 'following_id',
        ]);
        $this->hasMany('Followings', [
            'through' => 'ActiveFollowings',
            'propertyName' => 'Followers',
        ]);
  

CakePHP4にて、フォロー機能を実装する手順④フォローされる側の目線で考える

1行目:まずはFollowsモデル(ここではPassiveFollowings)について記述
上記の「CakePHP4にて、フォロー機能を実装する手順②モデルを2つに分けて考える」ところで説明済み。
2行目:PassiveFollowingsを介してフォローした人を集める
PassiveFollowingsを通ってフォローされた人を集める。フォローされた人を集めるには、"Followings"モデルを参照することになるため、propertyName: :Followingsを記述する。この一連の流れを"Followers"と命名したのでhasMany('Followers')と記述する。
/src/Model/Table/MembersTable.php
  
        $this->hasMany('PassiveFollowings', [
            'className' => 'Follows',
            'foreignKey' => 'follower_id',
        ]);

        $this->hasMany('Followers', [
            'through' => 'PassiveFollowings',
            'propertyName' => 'Followings',
        ]);
  
最終的に、Membersモデル・Followsモデルに追記する記述は以下のようになります。
/src/Model/Table/FollowsTable.php
  
        $this->belongsTo('Followings', [
            'className' => 'Members',
            'foreignKey' => 'follower_id',
        ]);

        $this->belongsTo('Followers', [
            'className' => 'Members',
            'foreignKey' => 'following_id',
        ]);
  
/src/Model/Table/MembersTable.php
  
        $this->hasMany('ActiveFollowings', [
            'className' => 'Follows',
            'foreignKey' => 'following_id',
        ]);
        $this->hasMany('Followings', [
            'through' => 'ActiveFollowings',
            'propertyName' => 'Followers',
        ]);
        $this->hasMany('PassiveFollowings', [
            'className' => 'Follows',
            'foreignKey' => 'follower_id',
        ]);
        $this->hasMany('Followers', [
            'through' => 'PassiveFollowings',
            'propertyName' => 'Followings',
        ]);
  
これにて、アソシエーションの実装は完了。

CakePHP4にて、フォロー機能を実装する手順⑤実際にフォローしているMember情報を取得

コントローラの中で、id=1のMemberがフォローしているMember(フォロー)の情報を取得します。
仮想のActiveFollowingsモデル・Followingsモデルをcontainする形です。
  
        $member = $this->Members->find('all', [
            'contain' => ['ActiveFollowings.Followings'],
            'conditions' => [
                    'Members.id' => 1
                ]
        ])->first();
  
取得結果はこんな感じ。見やすいように、上記コードのあと、コントローラの中でjsonを返すようにしています。
プロパティ「active_followings」内に、フォローしているMember一覧が、
中のプロパティ「following」内に、Memberの情報が取得されているのがわかります。

CakePHP4にて、フォロー機能を実装する手順⑥実際にフォローされているMember情報を取得

コントローラの中で、id=1のMemberがフォローされているMember(フォロワー)の情報を取得します。
仮想のPassiveFollowingsモデル・Followersモデルをcontainする形です。
  
        $member = $this->Members->find('all', [
            'contain' => ['PassiveFollowings.Followers'],
            'conditions' => [
                    'Members.id' => 1
            ],
        ])->first();
  
取得結果はこんな感じ。見やすいように、上記コードのあと、コントローラの中でjsonを返すようにしています。
プロパティ「passive_followings」内に、フォローされているMember一覧が、
中のプロパティ「follower」内に、Memberの情報が取得されているのがわかります。

まとめ

CakePHPでフォロー機能を実装するノウハウって意外とネットにないので、理解と実装に結構な時間を要しました。
こちらの記事に改めて感謝です。
記事でも書いているとおり、
「1つのモデルを、仮想の2つのモデルに分けて考える」ことに慣れれば、
大体わかってくると思います。
苦しんで理解したことを書いているため、この記事もだいぶわかりづらくなっているかもしれません(すいません・・・)。まだ私も理解を進めている最中です。
苦しんで理解するで身につくこともあるかと思いますので、みなさんも苦しんで理解してください(笑)
この記事に誤りや語弊があれば、フィードバックをお願いいたします!

≫ Read More

CakePHP 2021/01/31morishi

【jQuery】1つのセレクトボックスの選択値に応じて、他のセレクトボックスの内容を切り替える機能を実装

フォームを実装する機会があり、「地方選択」セレクトボックスにて選択した内容に応じて、「都道府県選択」セレクトボックスの選択肢を変更する必要がありました。jQueryを用いた簡単な実装ですが、スニペットとして記事に保存しておきます。

今回は例として、こんな2つのセレクトボックスを作成しました。

①「地方選択」セレクトボックスと「都道府県選択」セレクトボックスがある
②「地方選択」セレクトボックスで任意の地方を選択すると、
選択した地方に対応した都道府県が「都道府県選択」セレクトボックスに設定される

↓こんな感じです。

↓実装コードはこちら。
  
    <script>
    // 各地域ごとの都道府県の配列を設定
    var hokkaido = {1:'北海道'};
    var tohoku = {2:'青森県', 3:'岩手県', 4:'宮城県', 5:'秋田県', 6:'山形県', 7:'福島県'};
    var kanto = {8:'茨城県', 9:'栃木県', 10:'群馬県', 11:'埼玉県', 12:'千葉県', 13:'東京都', 14:'神奈川県'};
    var chubu = {15:'新潟県', 16:'富山県', 17:'石川県', 18:'福井県', 19:'山梨県', 20:'長野県', 21:'岐阜県', 22:'静岡県', 23:'愛知県'};
    var kinki = {24:'三重県', 25:'滋賀県', 26:'京都府', 27:'大阪府', 28:'兵庫県', 29:'奈良県', 30:'和歌山県'};
    var chugoku = {31:'鳥取県', 32:'島根県', 33:'岡山県', 34:'広島県', 35:'山口県'};
    var shikoku = {36:'徳島県', 37:'香川県', 38:'愛媛県', 39:'高知県'};
    var kyushu = {40:'福岡県', 41:'佐賀県', 42:'長崎県', 43:'熊本県', 44:'大分県', 45:'宮崎県', 46:'鹿児島県', 47:'沖縄県'};
    // 各地域を配列にまとめる
    var areaArray = [hokkaido, tohoku, kanto, chubu, kinki, chugoku, shikoku, kyushu];

    $(function() {
      // 地域選択用セレクトボックスが切り替わったら発動
      $('#areaSelect').change(function() {
        // 一旦、都道府県選択用セレクトボックスのoptionを消去
        $('#pref > option').remove();
        // 地域選択用セレクトボックスの値を取得
        var val = $(this).val();
        // 選択したvalue値を変数に格納
        var selectedArea = areaArray[val];
        // 選択した地域の都道府県をセレクトボックスのoptionに追加
        $.each(selectedArea, function(index, value){
          $('#pref').append($('<option>').html(value).val(index));
        })
      });
    });
    </script>

  <select class="areaSelect" id="areaSelect">
    <option>地域を選択してください</option>
    <option value="0">北海道</option>
    <option value="1">東北</option>
    <option value="2">関東</option>
    <option value="3">中部</option>
    <option value="4">近畿</option>
    <option value="5">中国</option>
    <option value="6">四国</option>
    <option value="7">九州</option>
  </select>

  <select class="pref" id="pref">
  </select>
  
↓同様の実装をされている方がいました。
こんな方法もあるようです。

≫ Read More

HTML/CSS/JavaScript 2021/02/28morishi