[cakephp: CakePHP2 note] CakePHP2 note. #php #cakephp
version3 と違い古いシステムでの利用が想定される。PHPのバージョン新しめの機能 ( array() -> [] ) とかは使わないほうが無難。ORMで取得するのが連想配列だったりなかなか負の遺産だけどCakePHPの稼働バージョンで一番多いのはこいつ。
http://www.cxmedia.co.jp/school/cakephp_doc/core-utility-libraries/app.html
http://qiita.com/katsuakikon/items/7a8fcaf85b342cb61bcc
Configure::load('functions');
記述Configure::write('Session', array(
'defaults' => 'php',
'timeout' => 2160, // 36 hours
'ini' => array(
'session.gc_maxlifetime' => 129600 // 36 hours - こいつを timeout より長くしないと意味ない
)
));
https://book.cakephp.org/2.0/ja/core-libraries/behaviors/containable.html
// Contain Sample
$this->Seat->Behaviors->attach('Containable');
$seats = $this->Seat->find('all', array(
'contain' => array('Event', 'Seat', 'Student', 'SeatVote' => array('Company')),
'conditions' => array('Seat.event_id' => $event_id),
'order' => array('Seat.position' => 'asc'),
'recursive' => 2,
));
このコントローラのどこでも使うよ : public $uses = array('Model1, 'Model2);
この処理でしか使わないよ : $this->loadModel('Model1');
$this->loadModel()
のが早いけど使いすぎると依存関係がごちゃる。複数のモデルと連携するコントローラクラスなのか、特定エンティティ(モデル)に特化したコントローラなのか設計段階で決めておくべき。
IEとかなら大丈夫。セキュリティ頑張るブラウザだとNGのよう。 以下でsessionのAgentチェックを無効にすると別タブログインOKに。
// core.php
Configure::write('Session.checkAgent', false);
as みたいなやつ http://qiita.com/kazu56/items/82e049118a70a735fdc7
if($this->request->data['User']['name'])
だと 空値で notice 。isset()
と組み合わせると冗長になるので data()
メソッドを使う if ($this->request->data('User.name'))
でアクセスすると存在しない場合にエラーにならないので便利。
AuthComponent::password()
でOK
booleanのフォームインプットの値が true , false ではじかれた...?←未検証
'fields'=>array('DISTINCT table.id'....); 上記のようにfieldsオプションの中で重複削除の基準になるカラムを指定してあげれば返り値 $query とかには重複したものは入らなくなる。ちなみにfieldsの先頭に書かないとエラー。 http://wataame.sumomo.ne.jp/archives/1235 また、find('count')のオプションでDISTINCTを使う場合、fieldsに配列で他の指定をするとアウト。http://book.cakephp.org/2.0/ja/models/retrieving-your-data.html#find-count
// 規約通りでない(くそみたいな)DB構成のときにキーの再設定が可能
public $primaryKey = 'no';
//複数指定するといみわからんくなる
public $primaryKey = array('id','no');
https://teratail.com/questions/10090
page:2
とかは $this->params['named']['page']
にいるよ
public $pagenate = array('諸々');
で設定しろってマニュアルに書いてあるくせにきかねえぞこらってときはコンポーネントロード時に配列でオプション渡したれ。そもそもControllerに定義した$pagenateにはアクセスしていない。$pagenateの設定を反映させるには、コンポーネントコンストラクタの引数に渡す/コンポーネントのインスタンスの内部変数書き換え(多分 $this->Paginator->settings=array()
だね)/リクエスト時にパラメータとして渡す。https://blog.doizaki.com/entry/2015/04/21/001600
$count = $this->Model->find('count');
$limit = 5000;
$loop = ceil($count / $limit);
for ($i = 0; $i < $loop; $i++){
$offset = $limit * $i;
$data = $this->Model->query("select * from hogehoge as limit {$limit} offset {$offset};", $cachequeries = false);
// do something
}
$this->log($this->{$this->modelClass}->getDataSource()->getLog());
// default-dest: `tmp/logs/error.log`
// require: `CakeLog::config('default', array('engine' => 'File'));` in `bootstrap.php`
/**
* Model -> loadModel()
* @param str $model_name
* @return - (getting available loadModel() at ModelArea)
*/
public function loadModel($model_name) {
App::uses($model_name,'Model');
$this->{$model_name} = new $model_name();
}
// $this->loadModel('User');
// $this->User->find('first');
// in class AppAdminsController extends AppController {
public function beforeFilter() {
parent::beforeFilter(); // extend parent method
// set auth component
$this->layout = 'admin';
$this->Auth->loginRedirect = array('controller' => 'admins', 'action' => 'index');
$this->Auth->logoutRedirect = array('controller' => 'admins', 'action' => 'login');
$this->Auth->loginAction = array('controller' => 'admins', 'action' => 'login');
$this->Auth->authenticate = array(
'Form' => Array(
'fields' => Array(
'username' => 'username',
'password' => 'password',
),
'userModel' => 'Admin', // "$useTable = 'users'" in App\Model\Admin
),
);
AuthComponent::$sessionKey = "Auth.Admins"; // for another Auth
// check & redirect by authority
$allowActions = array('login', 'logout', 'api');
$this->Auth->allow($allowActions);
if (!in_array(strtolower($this->request->action), $allowActions)) {
if (!$this->Auth->loggedIn()) {
$this->Flash->error(MSG_ERROR_LOGIN);
$this->redirect($this->Auth->logout());
}
if ($this->Auth->user('group_id') != 1) {
$this->Flash->error(MSG_ERROR_ROLE);
$this->redirect($this->Auth->logout());
}
}
}
// associated : Student hasMany Seat
// in StudentsController extends AppController
public $components = array(
'Paginator' => array(
'Student' => array(),
'Seat' => array(
'fields' => 'Seat.*, Student.*',
'limit' => 30,
'order' => array('Student.namekana1' => 'asc', 'Student.namekana2' => 'asc'),
'recursive' => -1, //disuse join
'joins' => array(
array(
'table' => 'students',
'alias' => 'Student',
'type' => 'LEFT',
'conditions' => 'Student.id = Seat.student_id',
),
),
),
),
);
public function index() {
$options = array();
$event_id = Sanitize::clean($this->request->query('event_id'));
$studentid = Sanitize::clean($this->request->query('studentid'));
$email = Sanitize::clean($this->request->query('email'));
$name1 = Sanitize::clean($this->request->query('name1'));
$name2 = Sanitize::clean($this->request->query('name2'));
$this->set(compact('event_id', 'studentid', 'email', 'name1', 'name2'));
if (!empty($studentid)) { $options += array('Student.studentid'=>$studentid); }
if (!empty($email)) { $options += array('Student.email like'=>'%'.$email.'%'); }
if (!empty($name1)) { $options += array('Student.name1 like'=>'%'.$name1.'%'); }
if (!empty($name2)) { $options += array('Student.name2 like'=>'%'.$name2.'%'); }
if (!empty($event_id)) {
$options += array('Seat.event_id' => $event_id);
$this->set('students', $this->paginate('Seat', $options));
} else {
$this->set('students', $this->paginate('Student', $options));
}
$this->loadModel('Event');
$eventOptions = $this->Event->getOptions();
$this->set(compact('eventOptions'));
}
// http://qiita.com/uedatakeshi/items/780189183eb3a61d5bdc
public function saveNewMember() {
$this->Comment = new Comment();// 別モデル読み込み
$datasource = $this->getDataSource();
try{
$datasource->begin();
$data = array(
'Member' => array(
'name' => 'maeda',
'email' => 'maeda@sample.com',
));
if (!$this->save($data)) {
throw new Exception();
}
$data = array(
'Comment' => array(
'post_id' => '4',
'comment' => 'res3-1',
));
if (!$this->Comment->save($data)) {
throw new Exception();
}
$datasource->commit();
} catch(Exception $e) {
$datasource->rollback();
}
}
// in model
// refs: http://log.noiretaya.com/157
$this->getDataSource()->fetchAll('
select * from users where username = :username and password = :password',
array('username' => 'jhon','password' => 'test@example.com')
);
// https://book.cakephp.org/2.0/ja/models/saving-your-data.html#hasmany
// Controller/CourseMembershipController.php
class CourseMembershipsController extends AppController {
public $uses = array('CourseMembership');
public function index() {
$this->set(
'courseMembershipsList',
$this->CourseMembership->find('all')
);
}
public function add() {
if ($this->request->is('post')) {
if ($this->CourseMembership->saveAssociated($this->request->data)) {
return $this->redirect(array('action' => 'index'));
}
}
}
}
// View/CourseMemberships/add.ctp
<?php echo $this->Form->create('CourseMembership'); ?>
<?php echo $this->Form->input('Student.first_name'); ?>
<?php echo $this->Form->input('Student.last_name'); ?>
<?php echo $this->Form->input('Course.name'); ?>
<?php echo $this->Form->input('CourseMembership.days_attended'); ?>
<?php echo $this->Form->input('CourseMembership.grade'); ?>
<button type="submit">Save</button>
<?php echo $this->Form->end(); ?>
// 重要
// hasOne or belongsTo を保存時と hasMany を保存時で用意する配列が違うのでビューを工夫する必要があるよ!!
// hasOne / belongsTo
$data = array(
'User' => array('username' => 'billy'),
'Profile' => array('sex' => 'Male', 'occupation' => 'Programmer'),
);
// hasMany
$data = array(
'Article' => array('title' => 'My first article'),
'Comment' => array(
array('body' => 'Comment 1', 'user_id' => 1),
array('body' => 'Comment 2', 'user_id' => 12),
array('body' => 'Comment 3', 'user_id' => 40),
),
);
// refs: http://norm-nois.com/blog/archives/2914
$db = ConnectionManager::getDataSource('default');
$tables = $db->listSources();
$config = $db->config;
foreach($tables as $table) {
exec('mysqldump --host='.$config['host'].' --user='.$config['login'].' --password='.$config['password'].' '.$config['database'].' '.$table.' > '.$table.'.sql');
exec('gzip -f '.$table.'.sql'); // zipのがいいか?
}
// refs
// https://book.cakephp.org/2.0/ja/installation/advanced-installation.html
{
"name": "project-name",
"repositories": [
{
"type": "pear",
"url": "http://pear.cakephp.org"
}
],
"require": {
"cakephp/cakephp": ">=2.6.4,<3.0.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.37",
"cakephp/debug_kit" : ">=2.2.4,<3.0.0"
}
}
// recursive : -1 でアソシエーション無効
$this->Model->recursive = -1;
$this->Model->find('all', array('conditions'=>array('code'=>'1')));
// option配列につっこめる
$programs = $this->Program->find('all', array('recuresive' => -1));
// paginationでも同じ
public $paginate = array(
'fields' => array('Event.*'),
'limit' => 10,
'order' => array('Event.date' => 'desc'),
'recursive' => -1, //disuse join
);
// Call Another Class
App:import('ClassName', 'Model');
$this->Another = new Another();
$this->Another->find('all');
// get webroot
echo $this->webroot;
echo $this->request->webroot;
echo Router::url( "/" );
echo $this->Html->url( "/" );
// get now *
$this->modelClass // in controller
$this->name; // in all mvc
$this->action // in controller or view
router::reverse($this->request) //path with query
router::reverse($this->request,true) //fullpath
http://monmon.hateblo.jp/entry/20110207/1297068346
http://dim5.net/cakephp/conditions-find.html
// base
$this->find('all',$conditions);
// OR (same column)
$this->find('all', array(
'conditions' => array(
'OR' => array(
array('user_id' => 1),
array('user_id' => 3),
),
),
),
);
// OR (diffrence columns)
$this->find('all', array(
'conditions' => array(
'id' => 1,
array('OR' => array(
'status' => 1,
'flg' => 1,
)),
array('OR' => array(
'status' => 2,
'flg' => 2,
)),
),
));
// LIKE
$data = $this->MODEL->find('all', array(
'conditions' => array(
'MODEL.tag like' => "%{$query_param}%",
'MODEL.status' => '1'
),
)
);
// NOT
$data = $this->MODEL->find('all', array(
'conditions' => array(
'Model.status' => '1',
'NOT' => array(
'Model.tag' => ""
)
),
)
);
// AND & OR
$data = $this->MODEL->find('all', array(
'conditions' => array(
'and' => array(
'MODEL.email' => $param[0][MODEL]["email"],
'MODEL.id <' => $param[0][MODEL]["id"],
'or' => array(
array('MODEL.status' => 1),
array('MODEL.status' => 3),
)
)
),
)
);
// findBy, findAllBy - findBy('カラム条件', fields, order, recursive)
$this->findById(8); // = find('first', ['conditions' => ['id' => 8]])
$this->findAllByName('hoge'); // = find('all', ['conditions' => ['name' => 'hoge']])
// getLastInsertId
$this->Model->getLastInsertID();
// saveAll ( save MultiArray and Associated )
$data = array(
'User' => array(
0 => array('name'=>'taro'),
1 => array('name'=>'jiro'),
)
);
$this->saveAll($data['User']);
// validation control
'isUnique' => array( // validation name
'rule' => array('isUnique'), // validate type
'message' => 'inputs exists!!',
'on'=>'create', // create only
// Component and Helper
public $components = array('Auth', 'Session', 'Cookie', 'Flash', 'MyComponent');
public $helpers = array('Html', 'Form', 'MyHelper');
// Branch request
if ($this->request->is('post')) {}
// data()
$this->request->data('User.name')
// safe call : $this-request->data['User']['name']
// loadModel
$this->loadModel($table);
$this->$table = new $table();
$query = $this->$table->find('all', $options);
// find in controller
$results = $this->{Model}->find('all);
foreach ($results as $result) {
echo $result['Model']['column'];
}
$this->set(compact('results'));
// Session Component
public $components = array('Session'); //prepare
$this->Session->write('key','value'); //write
$this->Session->read('key'); //read
$this->Session->check('key'); //isset
$this->Session->delete('key'); //delete
$this->Session->destroy(); //delete-all
// Flash Component
public $components = array('Session', 'Flash'); //prepare
$this->Flash->success('oh yeah!');
$this->Flash->error('fxxk!!');
// Create URL by Router class
Router::url(array('controller'=>'hoge',action'=>''));
// set view var
$this->set(compact('hogehoge'));
// get view var
$this->viewVars['hogehoge'];
// call another action
$this->actionName() //not api
// change action
$this->requestAction('hoge');
// change action without redirect
$this->setAction('hoge');
/* note
render hoge's View.
And thereafter, the process returns to the original action.
*/
// change render (view)
$this->render('hoge);
// change layout
$this->layout = 'default';
//default.ctp
// Redirect (with exit)
$this->redirect(['controller'=>'orders','action'=>'confirm',7]);
$this->redirect('http://example/orders/confirm');
$this->redirect($this->referer());
$this->redirect(array('action'=>'hoge',$param));
// Sanitize (DEPRECATION)
App::uses('Sanitize', 'Utility');
$param = Sanitize::clean($param);
// ConnectionManager (DEPRECATION)
App::uses('Model','ConnectionManager');
$db = ConnectionManager::getDataSource('default');
$result = $db->query('select * from datatable1');
// get view var
<?php echo $this->get('hoge') ?>
// insert str before (after) input
<?php echo $this->Form->input('hoge',array('after'=>'円')) ?>
// form input defaults
<?php echo $this->Form->create('User', array(
'inputDefaults' => array(
'label' => false,
'div' => false
))) ?>
// file upload form
echo $this->Form->create('User',array(
'enctype'=>'multipart/form-data',
));
echo $this->Form->file('image');
// in controller
// $tmp_name = $this->request->['User']['image']['tmp_name'];
// disabled, readonly in select
<?php echo $this->Form->input('piyo',array(
'type' => 'select',
'empty' => ' select here !!',
'options' => array(
1 => $options[1],
2 => $options[2],
3 => $options[3],
4 => $options[4],
),
'disabled' => array(1,2,3),
)) ?>
// link
$this->html->url(array('controller'=>'hoge', 'action'=>'index'));
// html5 input api
echo $this->Form->control('date', array('type' => 'date'));
// disuse escape (using fontawesome)
$this->Html->link('<i class=fa fa-file></i> ADD', array('controller' => 'users', 'action' => 'add'), array('escape' => false));
大量の DB データ(数十万件~)を取得してプログラムのメモリに格納してごにょるようなケースでは、データ量によっては「メモリ不足で落ちて」しまう。これについて一度に数千件ずつ取得するようなループを組み対処すると、今度はある一定量を超えた段階でブラウザが「サーバからの応答なし=タイムアウト」で落ちてしまう。このような 絞り込みを行った上で数万に達するようなテーブルを扱う 場合にはサーバサイドでタスクを「DBアクセス→データ取得」「待機ページ→データ取得完了後に出力ページ」のように2つに分割し PHPで非同期処理を行う 必要がある。以下サンプルコード。
App::uses('AppShell', 'Console/Command');
App::uses('User', 'Model');
/**
* FugeExportShell
* @see https://goo.gl/grcoHk
* @package app.Console.Command
*/
class FugeExportShell extends AppShell {
public $uses = array('User');
/**
* test method
* @param mix $args
* @return mix $args
*/
public function hello() {
$this->out('hello, world.'); //stdout
}
/**
* main: called default method by exec()
* get huge data using with splitting query by loop
*/
public function main() {
ini_set('memory_limit', -1);
set_time_limit(0);
$args = unserialize($this->args[0]);
$tmpfile = $args['tmpfile'];
$params = $args['params'];
$count = $this->DenpyoTbl->find('count', $params);
$limit = 5000; // get records number per loop
$loop = ceil($count / $limit);
for ($i = 0; $i < $loop; $i++){
$offset = $limit * $i;
$paramsWithOffset = $params;
$paramsWithOffset += array('limit' => $limit, 'offset' => $offset);
$rows = $this->User->find('all', $paramsWithOffset);
foreach ((array)$rows as $row) $results[] = $row;
if ($i > 0 && !file_exists(ROOT . DS . APP_DIR . DS .'tmp' . DS . $tmpfile.'__progress.txt')) exit;
$fp_progress = fopen(ROOT . DS . APP_DIR . DS .'tmp' . DS . $tmpfile.'__progress.txt', 'w');
fprintf($fp_progress, round((count($query)/$count * 100), 1));
fclose($fp_progress);
}
$serializedResults = serialize($results);
$fp_results = fopen(ROOT . DS . APP_DIR . DS .'tmp' . DS . $tmpfile.'.txt', 'w');
fprintf($fp_results, $serializedResults);
fclose($fp_results);
exit;
}
}
public function async(){
$this->autoLayout = false;
$this->autoRender = false;
$params = [/* something */];
$tmpfile = 'tmpfile';
$token = session_id();
$querystring = http_build_query(compact('tmpfile', 'token'));
$args = serialize(compact('tmpfile', 'params'));
// running async process by shell (FugeExportShell)
exec(ROOT.DS.APP_DIR.DS.'Console'.DS."cake fuge_export > /dev/null main '{$args}' &");
echo "
<script>
window.onload = function() {
setTimeout(function(){
location.href = '/{$this->request->controller}/await?{$querystring}';
}, 1000);
}
</script>
";
echo "<p>Loading... <span id=\"progress\">0</span> %</p>";
exit;
}
public function await() {
$this->autoLayout = false;
$this->autoRender = false;
if (session_id() != $this->request->query('token')) throw new BadRequestException();
$tmpfile = $this->request->query('tmpfile');
$token = $this->request->query('token');
$querystring = http_build_query(compact('tmpfile', 'token'));
if (!file_exists(ROOT . DS . APP_DIR . DS .'tmp' . DS . $tmpfile.'.txt')) {
$progress = (float)file_get_contents(ROOT . DS . APP_DIR . DS . 'tmp' . DS . $tmpfile.'__progress.txt');
echo "
<script>
window.onload = function(){
setTimeout(function(){
location.href = '/{$this->request->controller}/await?{$querystring}';
}, 1000);
}
</script>
";
echo "<p>Loading... <span id=\"progress\">{$progress}</span> %</p>";
if ((int)$progress == 100) {
echo "<p>データ取得完了</p>";
echo "<p>ページレンダリング中...しばらくお待ちください。</p>";
}
} else {
$results = unserialize(file_get_contents(ROOT . DS . APP_DIR . DS . 'tmp' . DS .$tmpfile.'.txt'));
unlink(ROOT . DS . APP_DIR . DS .'tmp' . DS . $tmpfile.'.txt');
unlink(ROOT . DS . APP_DIR . DS .'tmp' . DS . $tmpfile.'__progress.txt');
$this->setAction('export', $results);
}
}
public function export($results) {
$this->autoLayout = false;
foreach ($results as $result) { /* ごにょごにょ */ }
/* CSVで出すなりHTML出力するなり */
}
公式のアップグレードガイドを参考にしつつ https://goo.gl/FDscWi 大体のプロジェクトでは規約をちょい破ってるのでそこを手作業でかばあするhttps://goo.gl/cbrba5
$form->
などコンポーネント全て $this->Form
などへ$this->Auth->user();
→ $this->Auth->login();
initialize()
とかApp::uses()
で読むApp::import()
で読む$this->data
> $this->request->data
$this->params['url']['url']
> $this->request->url
$this->params['contoller']
> $this->request->controller
$this->params['action'] or $this->action
> $this->request->action
$this->params['pass'] or $this->passedArgs
> $this->request->pass
$this->params['named'] or $this->passedArgs
> $this->request->named
$this->request->params
> $this->request->query
へ$this->header
> $this->request->header
find($conditions)
> find('all', $conditions)
App::import(モデル)
> ClassRegistry::init()
$this->cakeError
> Exception, ExceptionRender 利用$this->log()
> CakeLog::config
利用/*
Sample Common CRUD API in CakePHP2 AppController
===
RESTっぽいやつ。
ControllerをApiにしてView側JSからAjaxする想定。
## Auth認証
リダイレクトが発生するとAjaxはセキュリティの都合上大体無効化される。よって `$this->Auth->allow('action_name');` とかでまずは認証スルーさせる。手書きで二重チェックしたり Flash 仕込んだりしてるときは勿論そっちもスルーするように。その後認証が必要なケースのみ api メソッド(アクション)内で `$this->Auth->loggedIn()` とかで振り分け。
また、認証の是非 `$this->Auth->loggedIn()` についてはCake側でCookie/Sessionで管理しており通常のJS経由Ajaxなら問題なくログイン済みかどうかの判定が行われる。が、DHC RestClient なんかのブラウザツールだとはじかれるので注意。(ブラウザツールでデバッグするときはAjaxに対するAuth認証を解除する必要あり。
## JSONレスポンスにするために
加えて、ヘッダーにコンテンツタイプJSON指定してjson_encodeしたいところだけど `header()` 自体がCake制御下なので `return new CakeResponse()` してやる。これ3系だとレスポンスタイプ指定できるよね。もしかして2系でもできたのかな。
*/
/**
* [api] ajax api base method
* @param str $request
* @return void
* @throws BadRequestException
*/
public function api() {
$this->autoRender = false;
$allowedMethods = array(
'get' => 'get',
'post' => 'post',
'put' => 'put',
'delete' => 'delete',
);
if ( /* remove this in debug by DHC REST Client */
!$this->Auth->loggedIn() ||
!$this->request->is('ajax') ||
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest' ||
empty($method = array_search(strtolower($_SERVER['REQUEST_METHOD']), $allowedMethods))
) {
throw new BadRequestException();
}
return $this->{'_'.$method}($this->request);
}
/**
* print json response
* @param array $results
* @param mix $debug
* @param string $successMessage
* @param string $errorMessage
* @return json CakeResponse [bool $status, int $code, str $message, array $response, mix $debug]
*/
protected function _printJsonResponse(
$results, // data type of array
$debug=null, // unset this param when product mode
$successMessage='processing done.',
$errorMessage='error has occurred.'
) {
if($status = !empty($results)){
$code = 200;
$message = $successMessage;
$response = $results;
} else {
$code = 404;
$message = $errorMessage;
$response = [];
}
if (!Configure::read('debug')) { unset($debug); }
return new CakeResponse(array('type' => 'json', 'body' => json_encode(compact('status', 'code', 'message', 'response', 'debug'))));
}
/**
* [api:get] find existing resource
* @param array $this->request
* @return json CakeResponse
*/
private function _get($request) {
unset($request->query['url']);
if ( /* use findAllBy() magic method */
// algorithm of to adjust query-string for findAllBy()
// ["url?findAllBy=Id&args=8" => "findAllById(8)"]
isset($request->query['findAllBy'])) {
$findAllBy = $request->query['findAllBy'];
$args = $request->query['args'];
$rows = $this->{$this->modelClass}->{'findAllBy'.$findAllBy}($args);
} else { /* use find('all') method with conditions */
// algorithm of to adjust query-string for like-search
// ['__'=>'.', '.like'=>' like', '*'=>%]
foreach ((array)$request->query as $key => $value) {
$adjustedKey = str_replace('.like', ' like', str_replace('__', '.', (string)$key));
$adjustedValue = str_replace('*', '%', (string)$value);
$conditions[] = array((string)$adjustedKey => (string)$adjustedValue);
}
// access to resource
$options = (empty($request->query)) ? null : array('conditions' => $conditions) ;
$rows = $this->{$this->modelClass}->find('all', $options);
}
foreach ((array)$rows as $row) { $results[] = $row[$this->modelClass]; }
return $this->_printJsonResponse($results, $request, count($results).'items found.', 'not found.');
}
/**
* [api:post] create new resource
* @param array $this->request
* @return json CakeResponse
*/
private function _post($request) {
$params = array(); //create record's param
$saveData = array($this->modelClass => $request->data);
$this->{$this->modelClass}->create();
$this->{$this->modelClass}->save($saveData);
$id = $this->{$this->modelClass}->id;
$newRecord = $this->{$this->modelClass}->findById($id);
$results = $newRecord[$this->modelClass];
return $this->_printJsonResponse($results, $request, 'id:'.$id.' was created.', 'item not created.');
}
/**
* [api:put] update new resource
* @param array $this->request
* @return json CakeResponse
*/
private function _put($request) {
if ($id = $request->data('id')) {
$params = array();
$saveData = array($this->modelClass => $request->data);
$this->{$this->modelClass}->save($saveData);
$newRecord = $this->{$this->modelClass}->findById($id);
$results = $newRecord[$this->modelClass];
}
return $this->_printJsonResponse($results, $request, count($results).' items updated.', 'item not updated.');
}
/**
* [api:delete] delete exists resources
* @param array $this->request
* @return json CakeResponse
*/
private function _delete($request) {
if ($request->data('deleteAll')) { /* branch of delete or deleteAll */
$conditions = array(); //use $this->deleteAll()
foreach ((array)$request->data as $key => $value) {
if ($key == 'deleteAll') continue;
$adjustedKey = str_replace('__', '.', (string)$key);
$conditions[] = array((string)$adjustedKey => (string)$value);
}
$status = $this->{$this->modelClass}->deleteAll($conditions);
} else {
if ($id = $request->data('id')) {
$dependents = $request->data('dependents') ? true : false ;
$status = $this->{$this->modelClass}->delete($id, $dependents);
} else {
$status = false;
}
}
return $this->_printJsonResponse($status, $request, 'id:'.$id.' was deleted.', 'item not deleted.');
}