2016.11.23
0でもできるオブジェクト指向 with 出席管理マネージャー#3【一般化を考える】
ということで本日のテーマは
一般化でございます。
今回やりたいこととしては
指定されたユーザーが管理するグループのリストを取得するということですが、これをもう少し一般化して
データベースからリストを取得するというクラスを作ってみてはどうか、という話をしたいと思います。
こちらが今回のプロダクトの設計図・・・・・・というか
GUI遷移図といった方がいいですね。こんなものをイメージして作ってるというすっごい簡単な図です。
字があまりにも汚くて見づらいと思いますが、ログインしたら所属リストがばーって出てくる感じですね。
ちなみに、単にユーザーとして使用するだけなら利用登録なしで済ませたいので、右上にあります通り識別用のURLはグループIDとメールアドレスを使うんですが、メールアドレスをグループIDでハッシュしたものをURLにしたいなーと思ってるんですけど、できますかね(笑)(笑)
まぁそれはさておき、ここで図には書いてないのですが、リストには
管理リストと
所属リストの2種類を表示することになりそうなんですよね。
これを似たようなメソッドで呼び出すという考えで実装してみようと思うと、こうなりそうですよね。
class GetList
{
/*sample*/
//GetList user(int)
//db list = user->get_list()
//GetList admin(int,true)
//db admin_list = admin->get_list()
}
正直この実装はマズいんじゃないかって感じはしますけど、まぁとりあえずクラスとして作ってみます。
やってることとしては
コンストラクタでフラグを登録してるってことですね。
つまり、GetListクラスのインスタンスを生成する時、bool型の第二引数があれば、管理リストを呼び出す「設定にする」ということをやっております。
別にそんなん普通にメソッドの引数でいいやんって思うかも知れませんけど
後で引数を追加したい時に呼び出している箇所全ての訂正が必要になる可能性があるので、やっぱコンストラクタで済ませる方がラクかなって思います。まぁデフォルト引数とかありますけどね・・・・・・。
しかしこれを更に一般化します。
どういうことかというと、実はこのプロダクトは会員登録が必須でないんですね。
管理者になるためには会員登録が必須になる
(メールアドレスの間違いなんかあってはよくないですしね)のですが、ユーザーとして使う分には認証は別に要らないと思います。まぁほんとは認証させたいんですが、会員登録させるとなると使い勝手悪くなりますしね。
つまりユーザーリストはユーザーIDではなくメールアドレスから取得するのが一般的な動作になりそうです。
そのように書き換えてみると・・・・・・
//ログイン済→データベースからリストを取得
$admin=new AdminUser();
$list=new GetList($admin->id,true);
class GetList
{
/*sample*/
//GetList user(str)
//db list = user->get_list()
//GetList admin(int,true)
//db admin_list = admin->get_list()
// プロパティ
private $id=0;
private $email='';
private $admin_flag=false;
function __construct($email) {
$this->email=$email;
}
function __construct2($id,$bool) {
$this->id=$id;
$this->admin_flag=$bool;
}
}
※後述しますが、これは動かないコードです
まぁちょこっとコードが書き換わってますけど現状こんな感じです。
construct2でidにするかメールアドレスにするか悩みましたけど、まぁ汎用性の高そうなIDで・・・・・・
さて、PHPではコンストラクタが2つってのは実装できません。これがjavaとかとの大きな違いですね。不便極まりないです(笑)
そこでどう実装するのかというと
func_get_args()とかを使う・・・・・・
という話をしようと思いましたが、この例の場合
is_numeric()で分岐させた方が早そうですね。
ただ、せっかくオブジェクトを使っているのですし
オブジェクトごと渡してみましょう。
ちなみに余談ですけど、PHPでオブジェクトを渡した際は基本的には参照渡しになるそうです。
(※参考ページ)
ただ、ポインタがコピーして渡されるという仕組みっぽいので、メソッドでnullにしても意味ないって感じの動きをするそーです。記憶の片隅に置いとくと良さそうですね。
オブジェクトかどうかを判定するのは
is_object()ってのがありますので、こいつを使えば良さそうですね。
public function main(Request $request)
{
if (!Auth::check()) {
// ユーザーはログインしていない→ログインページへ
return view('index');
}
//ログイン済→データベースからリストを取得
$admin=new AdminUser();
$getlist=new GetList($admin);
$getlist_2=new GetList("hogehoge@hogehoge.com");//未登録ユーザー
echo '<PRE>';
var_dump(array(
$getlist->list_admin,
$getlist->list_user
));
echo PHP_EOL."--------------------------------".PHP_EOL;
var_dump($getlist_2->list_user);
echo '</PRE>';
}
class AdminUser
{
/*サンプルプログラム*/
//AdminUser admin(int)
//db $list = admin->group_list()
// プロパティ
public $id;
public $email;
function __construct() {
$this->id=Auth::user()->id;
$this->email=Auth::user()->email;
}
// メソッドの宣言
public function group_list() {
echo $this->id;
}
}
class GetList
{
/*sample*/
//GetList user(str)
//db list = user->get_list()
//GetList admin(int)
//db admin_list = admin->get_list()
// プロパティ
private $id=0;
private $email='';
public $list_admin;//管理グループリスト
public $list_user;//所属グループリスト
function __construct($var) {
if(!is_object($var)){
//渡された値が非オブジェクト(メールアドレス)であれば一般ユーザー
$this->email=$var;
$this->get_user();
return 1;
}
//渡された値がオブジェクト:ユーザーデータ
$this->id=$var->id;
$this->email=$var->email;
$this->get_admin();
$this->get_user();
return 1;
}
public function get_admin(){
//ユーザーIDから管理リスト取得
$this->list_admin = DB::table("administrators")
->where('a_u_id', '=', $this->id)
->join('groups', 'a_g_id', '=', 'g_id')
->get();//管理グループのリスト
}
public function get_user(){
//メールアドレスから所属グループリスト取得
$this->list_user = DB::table("lists")
->where('l_email', $this->email)
->get();//所属グループのリスト
}
}
長いですが、これがオブジェクト指向を意識して書いたコードになります。
だいぶすっきりして見やすい気がしますね。
えーと、全然話してないようなとこを書きながら変えてるので補足を。
まずやってみたこととしては
全てのリストを$getlistに集約したというところですね。
データベースからの取得は最初関数から呼び出そうかと思ったんですが、リスト取得用のインスタンスが生成された時点で
リストを生成することが分かりきっているという観点から、コンストラクタの時点でプロパティにリストを読み込ませています。
つまり、メールアドレスを用いてインスタンスが生成された時はget_user()のみが、IDを用いてインスタンスが生成された時は両方の関数が実行されることになり、インスタンスに値が代入されます。
あとは、ビューにこのインスタンスを渡せば簡単に検索結果が引き継げますね。
そして、ついでに非登録ユーザーのテストもしました。それが$getlist_2ですね。
こちらはメールアドレスを引数としたコンストラクタを実行させています。
実行結果はこちら。ちょっと実在するメールアドレスを使っちゃってるんでモザイクかけました(笑)
登録ユーザーであれ、グループリスト内では自由に名前が設定できるシステムにしたいので、2番グループに所属するリスト番号3の名前は「偽名」としています。
とりあえず、データ取得に関してはこれでイイ感じなので、後はHTMLでビューを作れば所属グループリストと管理グループリストの表示まで完成したことになりますね。
まぁほんとはメールアドレス検索とか不安要素でしかないのですが、レコードがそんな数万件にものぼるような大ヒットプロダクトになるとは思ってないし大丈夫でしょう(笑)(笑)
一致検索だとインデックス付けられなくてもそんなに心配なかったりしますかね・・・・・・?ただ仕様上どうしようもないんだよな・・・・・・。正規化したところで結局変わんないしなー・・・・・・。
まぁ、正規化しちゃってもいいんですけど、
所属グループごとにメールアドレスを変えたいとかいうオーダーに対応するかどうか決めてないので正規化はしないことにしてます。
おまけ。いまここまで作ったよ。
デザイン考えるのめんどくさいなぁ・・・・・・。