はじめに
会社に入社して会社行ものために、php(cakephp)を学ぶ研修で、cakePHPのチュートリアル(主にBlog)をしたときに、つまずいた点を記事として残そうかと思います。
*ブログチュートリアル
https://book.cakephp.org/3/ja/tutorials-and-examples/blog/blog.html
つまずいた所
*admin権限ではないユーザーがログインした場合のアクション権限
=>ユーザーが投稿した記事のみ編集・削除できる機能実装(ほんとに最後...)
ここにすごくcakephp初心者の自分は苦労しました...
認可(誰が何にアクセスするのを許可するか)
ログインしてるのか・してないかでアクセスを分ける
まずユーザーの種類にadmin(管理者)とauther(著者)の2種類あります。
そこの使い分けはまず、全体に認証をかけたいようなときはAppControllerappcontrollerでAuthコンポーネントの設定します。
*ちなみに、コントローラの拡張をコンポーネント!モデルはビヘイバー!Viewはヘルパーというものがあります。
publicfunctioninitialize(){$this->loadComponent('Flash');$this->loadComponent('Auth',[//Authコンポーネントの読み込み'authorize'=>['Controller'],'loginRedirect'=>[//ログイン後のリダイレクト先'controller'=>'Articles','action'=>'index'],'logoutRedirect'=>[//ログアウト後のリダイレクト先'controller'=>'Pages','action'=>'display','home']]);}
続きにAppContorollerに
//isAuthorizedはAuthコンポーネントで定義されている!publicfunctionisAuthorized($user){// roleというカラムで、adminを定義して管理者はすべての操作に権限を与えるif(isset($user['role'])&&$user['role']==='admin'){returntrue;}//その他のロールの場合はデフォルトで拒否とする(許可したい場合は各コントローラで個別に設定)returnfalse;}// 共通メソッド beforeFilterでコントローラーのメソッドよりも先に実行する(ロールバック)publicfunctionbeforeFilter(\Cake\Event\Event$event){//beforeFilterでisAuthorizedメソッドよりも先に実行してくれるので//認証なしでアクセスできるアクションの指定$this->Auth->allow(['index','view','display']);$this->set('auth',$this->Auth->user());}
ユーザーの権限
AppConroller 内でやるかわりに、 各個別のコントローラーにさらなるルールを追加します。
追加しようとしているルールというのは、 ArticlesController によって、著者は記事を作成できるが、 自分のものではない記事を編集・削除できないようにする、というもの(本題)。
まずはArticlesControllerの編集
//Authコンポーネントで定義されているメソッド(認証済みであるという意味)publicfunctionisAuthorized($user){//addアクションのリクエストであればtrueを返す = つまり登録ユーザー全員が記事を追加できますif($this->request->getParam('action')==='add'){// LoginUserであれば実行可能なので、trueを返すreturntrue;}//(in_array — 配列に値があるかチェックする) 編集や削除のリクエストである場合if(in_array($this->request->getParam('action'),['edit','delete'])){//pass.0はURL内で渡されたパラメータを表します、つまりURLのアクションの下のパスセグメント( / で区切ったキーワード)を数字をインデックスとする配列で呼べるようにする。//'pass.0' とインデックスを指定すると配列の先頭要素、つまりパスセグメントの先頭要素を取り出せる。$articleId=(int)$this->request->getParam('pass.0');// actionがedit,deleteの場合、request($articleId)の値とuserテーブルのuser_idの比較を行う。if($this->Articles->isOwnedBy($articleId,$user['id'])){//一致すればtrueを返して、編集削除を許可するreturntrue;}}// 比較がfalseの場合、AppControllerのisAuthorizedへ、// 権限が'admin'の場合はtrue、それ以外はfalse。returnparent::isAuthorized($user);}}
ちなみにisOwnedByはarticleテーブルで定義する!
publicfunctionisOwnedBy($articleId,$userId){return$this->exists(['id'=>$articleId,'user_id'=>$userId]);}
モデルのアソシエーション
関係するモデルはArticlesテーブルとUsersテーブルが関係あります。
ここが大事!
つまり、投稿した記事のidとログインしたuser_idとが紐付かなければなりません!
アソシエーションを組みます!
ArticlesTable
publicfunctioninitialize(array$config){parent::initialize($config);$this->table('articles');$this->displayField('title');$this->primaryKey('id');$this->addBehavior('Timestamp');// アソシエーション//*foreignKeyはリレーションする「先」のテーブルの、紐づけるカラム(外部キー)$this->belongsTo('Users',['foreignKey'=>'user_id']);$this->belongsTo('Categories',['foreignKey'=>'category_id']);}
*ここで迷ったのは、Userstable.phpもアソシエーション 定義しないでいいの???
今回は投稿した記事(=ArticlesControllerのaddアクションのみ)なのでいりません!!
これで、ArticlesControllerでusersテーブルでのデータを持ってくることができます!
最後にコントローラーのメソッド!!
投稿した記事(addアクション)にuser_idを紐付ける
// 記事追加機能publicfunctionadd(){//newEntityとは 新規追加、保存処理をするときに使用新しく保存されるときにデータの検証が行われる$article=$this->Articles->newEntity();//コントローラの処理でHTTPリクエストメソッドが「Post」でない場合はエラーに飛ばす、if($this->request->is('post')){//ここでuserテーブルのuser_idと紐付けてくれる(ここ大事です!!)$article->user_id=$this->Auth->user('id');// patchEntity メソッドは、データがエンティティーにコピーされる前に 検証を行います$article=$this->Articles->patchEntity($article,$this->request->getData());if($this->Articles->save($article)){$this->Flash->success(__('Your article has been saved.'));return$this->redirect(['action'=>'index']);}$this->Flash->error(__('Unable to add your article.'));}$this->set('article',$article);$categories=$this->Articles->Categories->find('treeList');$this->set(compact('categories'));}
これで無事に投稿した記事とuser_idが紐付きました!
先ほどArticlesControllerで定義したisAuthorizedメソッドが効いてアクセス制限を分けることができました!!
最後に
チュートリアルはここまで優しく書いてもないですし、理解するにのに苦労しました!
最後はわざと書いてません(多分..)
デバックしたりすることで、今回のエラーをがアソシエーション されてない事に気付き対処することができました!
参考
https://sites.google.com/site/kobashijiangyiyong/detabesu/e-detabesu-she-ji-yan-xi-3-4