CakePHP 一時的に違うモデルを利用する

PHP

CakePHP 一時的に違うモデルを利用する

CakePHP1.3

扱いたいデータが他のモデルの場合、次のようにすれば、ちゃちゃっとデータが取れます。

 $this->loadModel('モデル名');
 //例
 $this->loadModel('Article');
 $recentArticles = $this->Article->find('all', array('limit' => 5, 'order' => 'Article.created DESC'));

CakePHP 関連付けされていないモデルでfindする

 

CakePHP ログイン失敗などの場合のエラーメッセージを表示

PHP

CakePHP ログイン失敗などの場合のエラーメッセージを表示

CakePHP 1.3

Authの仕組みを使って、簡単にログインの仕組みを実装できますが、エラーメッセージの表示はusers_controller.phpやlogin.ctpに何か書く必要はありません。

まず、メッセージの表示のためにレイアウトファイルのctpファイル(default.ctp)に

 echo $this->Session->flash();
 echo $this->Session->flash('auth');

と書きます。

表示されるメッセージのカスタマイズは、app_controller.phpのfunction beforeFilter()に

 $this->Auth->loginError = "ログインに失敗しました。";
 $this->Auth->authError = "このページにはアクセスできません。";

などと書いておきます。
もちろん、Authコンポーネントなどは、読み込んである前提です。
http://book.cakephp.org/1.3/view/1252/Displaying-Auth-Error-Messages

CakePHP レイアウトを変更する

PHP

CakePHP

CakePHP 1.3

CakePHPページに応じてレイアウトを変更する

CakePHPはデフォルトだと、
views/layouts/default.ctp
というレイアウトを利用します。

全ページ同じレイアウトを利用したい場合、default.ctpを変更すればよいですが、コントローラーやアクションにより、レイアウトを切り替えたい場合は、次のようにします。
コントローラー内に次のように記述すると、レイアウトを変更できます。

 $this->layout = 'for_user';

同時にviews/layouts/にfor_user.ctpというファイルを作っておきます。
for_user.ctpが新しいレイアウトファイルとなります。

 

CakePHP リレーションを外す

PHP

CakePHP リレーションを外す

CakePHPがとても遅くなる場合があります。
CakePHPのよいところは、データベースのリレーションをモデルに定義しておけば、後は関係するデータをうまいこと取得してくれるところです。
しかし、これが仇をなしてひとつひとつの動作が遅くなってしまう場合があります。

たとえば、次のようなデータ構造があるとします。

 //師匠(Master)が多数の弟子(Student)を持つ
 Masterモデル hasMany Studentモデル

この時、Masterのデータは10件程度だとしても、Studentのデータ数が10万件ぐらいあるとすると、毎回次のようなMySQLのクエリが発行されます。

 //Masterのデータが1から16まである場合
 SELECT `Student`.`id`, `Student`.`name`, `Student`.`skill_id`,Student`.`master_id`,   
 `Student`.`contents`, `Student`.`age`, Student`.`comment`,`Student`.`created`, `Student`.`modified` 
 FROM `students` AS `Student` WHERE `Student`.`master_id` IN (1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16) 

これだけで相当時間とメモリを食います。
新規でデータを追加する際やデータを編集する場合には、この処理は不要です。

しかし、表示のためにrecursiveを‐1にすることができません。

そういう場合、一時的にMaster hasMany Studentsのリレーションを外すことができます。

 //動作が遅いので、Studentをバインドから外す
 //stutdents_controller.phpに記述
  $this->Student->Master->unbindModel(
  			array('hasMany' => array('Student'))
  	);

hasAndBelongsToManyの場合は次の通りです。

   			
 //動作が遅いので、Studentをバインドから外す
 //stutdents_controller.phpに記述
  $this->Student->Master->unbindModel(
  			array('hasAndBelongsToMany' => array('Student'))
  	);

CakePHP ユーザーのパスワード編集

PHP

Cake PHP ユーザー編集画面でのパスワード編集について

CakePHP 1.2.3.8166、
CakePHP 2.6.0

CakePHPではパスワードを自動的に暗号化してくれるのはよいのですが、ユーザー情報を編集する際にも自動で暗号化してくれるので、それだと2重に暗号化されて、パスワードが違ってしまいます。

いろんなやり方が紹介されてますが、一番スマートなのはこれかなぁ。

CakePHP 1.2.3.8166版

  1. ユーザー情報編集画面では、”password”という項目ではなく、”new_password”などの別の項目名を使う
  2. new_passwordが空でなければ、暗号化してpasswordに入れる

参考URL http://osdir.com/ml/CakePHP/2009-05/msg01819.html

以下の例は、上記URLからの抜粋

 if (!empty($this->data) {
  
  if (!empty($this->data['Model']['new_password'])) {
  $this->data['Model']['password'] = $this->Auth->password($this-
  >data['Model']['new_password'];
  }
 
 if ($this->Model->save($this->data) {
 // data saved
  }
 else {
 // there was an error in the form submission
  }
 
 }

CakePHP 2.6.0版

変わったのは、チュートリアルにあるように、ユーザーモデルでパスワードをSaveする時は、下記のやり方でパスワードをハッシュ化します。

 
 //User.php内
 	public function beforeSave($options = array()) {
 		if (isset($this->data[$this->alias]['password'])) {
 	        $passwordHasher = new SimplePasswordHasher();
 	        $this->data[$this->alias]['password'] = $passwordHasher->hash($this->data[$this->alias]['password']);
 	    }
 	    return true;
 	}

コントローラーでは下記の通り。

 //UsersController.php内
 	public function edit($id = null) {
 		$this->User->id = $id;
 		if (!$this->User->exists($id)) {
 			throw new NotFoundException(__('Invalid customer'));
 		}
 		
 		if ($this->request->is('post') || $this->request->is('put')) {
 
 			//パスワードがある場合のみパスワードをDBでUpdate
 			 if (!empty($this->request->data['User']['new_password'])) {
 		 		$this->request->data['User']['password'] = $this->request->data['User']['new_password'];		 		
 			}
 
 			if ($this->User->save($this->request->data)) {
 				
 				$this->Session->setFlash(EDIT_FINISH,'default',array('class' => 'set_message'));
 				return $this->redirect(array('action' => 'index'));
 			
 			} else {
 				$this->Session->setFlash(EROOR);
 			}
 		} else {
 			
 			 $this->request->data = $this->User->read(null, $id);
                        unset($this->request->data['User']['password']);
 		}
 		
 	}

ちなみに、これがベストな方法かはわかりません。
誰かもっとスマートな方法をしっていたら教えてください。