#CakePHP çéã§APIãå®è£ ãããã¥ã¼ããªã¢ã«

ã¹ãã¼ããã©ã³ã¢ããªã®ããã¯ã¨ã³ãããJSãã¬ã¼ã ã¯ã¼ã¯ã®ããã¯ã¨ã³ãã¨ãã¦ãJSONãXMLãè¿ãAPIããµã¼ããµã¤ãã§å®è£ ããæ©ä¼ã¯å¤ãã¨æãã¾ãã
ä»åã¯ãComposerã¨CakePHP2.4ãFriendsOfCake/crudã使ã£ã¦çéã§å®è£ ãã¦ã¿ã¾ãã
ã§ããããã¯ããã
slywalker/cakephp-app-api_sample
CakePHPã®ã¤ã³ã¹ãã¼ã«
ã¾ããããã¸ã§ã¯ãã®ãã£ã¬ã¯ããªã«composer.jsonãã¤ããã¾ã
composer.json
{
"require": {
"pear-cakephp/cakephp": "2.4.*"
},
"config": {
"vendor-dir": "Vendor/"
},
"repositories": [
{
"type": "pear",
"url": "http://pear.cakephp.org"
}
]
}
ã¤ã¥ãã¦composer.pharã®ãã¦ã³ãã¼ãã¨ããã±ã¼ã¸ã®ã¤ã³ã¹ãã¼ã«
$ curl -s http://getcomposer.org/installer | php $ php composer.phar install
ããã¦ãããã¸ã§ã¯ããBake
$ Vendor/bin/cake bake project $PWD --empty
ãã©ã¦ã¶ã§ã¢ã¯ã»ã¹ããã¨â¦

ã¯ãããã¤ãã®ç»é¢ç»å ´ï¼
ãã ããã®ã¾ã¾ã§ã¯CAKE_CORE_INCLUDE_PATHã絶対ãã¹ã«ãªã£ã¦ããã®ã§ããããã¤ããéã«ãã¡ã«ãªãã®ã§æ¸ãæãã¾ãã
webroot/index.php, webroot/test.php
define('CAKE_CORE_INCLUDE_PATH', ROOT . DS . APP_DIR . DS . 'Vendor' . DS . 'pear-pear.cakephp.org' . DS . 'CakePHP');
å¿ããã¡ãªã®ãConsole/cake.php
Console/cake.php
25c25 < $root = dirname(dirname(dirname(__FILE__))); --- > $app = dirname(dirname(__FILE__)); 29c29 < ini_set('include_path', $root . PATH_SEPARATOR . __CAKE_PATH__ . PATH_SEPARATOR . ini_get('include_path')); --- > ini_set('include_path', $app . $ds . 'Vendor' . $ds . 'pear-pear.cakephp.org' . $ds . 'CakePHP' . PATH_SEPARATOR . ini_get('include_path')); 35c35 < unset($paths, $path, $dispatcher, $root, $ds); --- > unset($paths, $path, $dispatcher, $app, $ds);
æå¾ã«ãdatabase.phpãbake
$ Console/cake bake db_config
ãã©ã°ã¤ã³ã®ã¤ã³ã¹ãã¼ã«
ä»åã®ç®çãFriendsOfCake/crudã¨cakephp/debug_kitãå
¥ãã¦ããã¾ããããcomposer.jsonã«æ¸ãè¶³ãã¾ãã
composer.json
{
"require": {
"pear-cakephp/cakephp": "2.4.*",
"cakephp/debug_kit": "~2.2",
"FriendsOfCake/crud": "3.*"
},
"config": {
"vendor-dir": "Vendor/"
},
"repositories": [
{
"type": "pear",
"url": "http://pear.cakephp.org"
}
]
}
Composerã§ã¤ã³ã¹ãã¼ã«ãã¾ãã
$ php composer.phar update
CakePHPããã©ã°ã¤ã³ãèªã¿è¾¼ãããã«è¨å®ãã¨ãã¾ãããã
Config/bootstrap.php
CakePlugin::loadAll();
Crudãã©ã°ã¤ã³ã®è¨å®ä»
ãã¦ãCrudãã©ã°ã¤ã³ã使ããããã«è¨å®ãã¦ããã¾ããããä»åã¯è©³ããã¨ãã¯çãã®ã§ãããï¼ãã¨æã£ããå ¬å¼ããã¥ã¡ã³ããåç §ãã¦ãã ããã
ä»åã¯ã.jsonã®ã¢ã¯ã»ã¹ã§JSONã®ã¬ã¹ãã³ã¹ã.xmlã®ã¢ã¯ã»ã¹ã§XMLã®ã¬ã¹ãã³ã¹ãè¿ãããã«ãã¾ããããã¨ãããã¨ã§routes.phpã«ããã追å ã
Config/routes.php
Router::parseExtensions('json', 'xml');
ããã¦ãAppController.phpãã´ãªã´ãªâ¦
Controller/AppController.php
<?php App::uses('Controller', 'Controller'); App::uses('CrudControllerTrait', 'Crud.Lib'); // ããæ¸ãã¨ã㦠class AppController extends Controller { use CrudControllerTrait; // ãã¬ã¤ã使ããï¼ãªãã¦ã¢ãã³ public $components = [ 'Session', 'RequestHandler', // ãããæ¡å¼µåã§å¦çãããã¦ãããã®ã 'Paginator' => [ 'paramType' => 'querystring' // APIã£ã½ãã¯ã¨ãªå½¢å¼ ], 'DebugKit.Toolbar' => [ 'panels' => ['Crud.Crud'] // Crudç¨ã®ããã«ãããã®ã ], 'Crud.Crud' => [ 'actions' => ['index'], // ã¨ããããindexã®ã¢ã¯ã·ã§ã³ã ã 'listeners' => ['Api'] // ApiListenerã使ãã ] ]; }
ããã£ï¼æºåã¯æ´ã£ãï¼
ãã¼ã¿ã®æºå
ä»åã¯MySQL使ãã¨ãããã¨ã§ãããããé¡ããã¾ãããµã³ãã«ãã¼ã¿ãgithubã®ã¬ãã¸ããªå
ã®Config/Schema/cakeapi.sql.gzã«ããã®ã§ã¤ã³ãã¼ããã¦ãã ããã
ã¡ãªã¿ã«ãã¡ãã£ã¨åã£ããã¨ããããã¨æã£ãã®ã§ãã¼ã¿ã¯æ±äº¬é§ ãä¸å¿ã¨ããã©ã³ãã ã®ä½ç½®æ å ±1ä¸ä»¶ã§ããgeometryåã使ã£ã¦ã¾ãã
Model
ããã£ã¨
Model/Geometry.php
<?php App::uses('AppModel', 'Model'); App::uses('Sanitize', 'Utility'); class Geometry extends AppModel { public $virtualFields = [ 'lat' => 'Y(`latlng`)', 'lng' => 'X(`latlng`)' ]; public function conditionCenter($queryParams) { $queryParams = Sanitize::clean($queryParams) + [ 'lat' => null, 'lng' => null ]; if ( !is_numeric($queryParams['lat']) || !is_numeric($queryParams['lng']) ) { return []; } return ["MBRContains( GeomFromText( Concat( 'LineString(', {$queryParams['lng']} + 1, ' ', {$queryParams['lat']} + 1, ',', {$queryParams['lng']} - 1, ' ', {$queryParams['lat']} - 1, ')' ) ), latlng )"]; } }
緯度çµåº¦ã¯ããã¼ãã£ã«ãã£ã¼ã«ãã使ãã¾ããä¸å¿ããã®ç¯å²æ¤ç´¢ããã«ã¡ã½ãããç¨æãã¦ã¾ãã
Controller
ãããã£ã¨
Controller/Geometries.php
<?php App::uses('AppController', 'Controller'); class GeometriesController extends AppController { public function beforeFilter() { $this->Crud->on('beforePaginate', function(CakeEvent $event) { $model = $event->subject->model; $request = $event->subject->request; $event->subject->paginator->settings += [ 'conditions' => [ $model->conditionCenter($request->query) ] ]; }); parent::beforeFilter(); } }
ã¯ããããã ãã§ãâ¦
ãã¯ï¼ãã¨æã£ããå ¬å¼ããã¥ã¡ã³ãã§ããããï¼
ã¬ã¹ãã³ã¹
ã§ã¯ã§ã¯ãã¢ã¯ã»ã¹ãã¦ã¿ã¾ãããã
http://localhost/geometries.json
{
"success": true,
"data": [
{
"Geometry": {
"id": "1",
"latlng": null,
"lat": "84.001196",
"lng": "191.951974"
}
},
{
"Geometry": {
"id": "2",
"latlng": null,
"lat": "51.617372",
"lng": "162.921083"
}
},
....
]
}
ããã¼ï¼20件表示ããã¦ã¾ãããããã¯Paginateã®ããã©ã«ãã ããã§ããã
ã¡ãªã¿ã«ã
http://localhost/geometries.json?limit=1
{
"success": true,
"data": [
{
"Geometry": {
"id": "1",
"latlng": null,
"lat": "84.001196",
"lng": "191.951974"
}
}
]
}
ããã¼ï¼å¹ãã¦ãå¹ãã¦ãã
ãã£ã±ããå
¨ä½ã®ä»¶æ°ã¨ããä½ãã¼ã¸ç®ã¨ãç¥ãããã§ãããããããªã¨ãã¯ApiPaginationListenerã追å ãããã§ãã
Controller/AppController.php
<?php class AppController extends Controller { use CrudControllerTrait; public $components = [ 'Crud.Crud' => [ 'actions' => ['index'], 'listeners' => [ 'Api', 'ApiPagination' // ããï¼ ] ] ]; }
ãã¦ãã©ãã ï¼
http://localhost/geometries.json?page=2&limit=3
{
"success": true,
"data": [
{
"Geometry": {
"id": "4",
"latlng": null,
"lat": "83.012136",
"lng": "165.754295"
}
},
{
"Geometry": {
"id": "5",
"latlng": null,
"lat": "123.59616",
"lng": "201.408059"
}
},
{
"Geometry": {
"id": "6",
"latlng": null,
"lat": "80.112906",
"lng": "177.030496"
}
}
],
"pagination": {
"page_count": 3334,
"current_page": 2,
"has_next_page": true,
"has_prev_page": true,
"count": 10000,
"limit": 3
}
}
ã¸ã¼(Ã3)ãããã¯APIã®åãæã«ããããã§ãããã
ã§ããCakePHPãè¿ããã¼ã¿é
åã£ã¦ã¢ãã«åãã¤ãã¦ã¦ããªããããã§ãããããããªã¨ãã¯ãApiTransformationListenerã使ã£ã¦ãã ããï¼
Controller/AppController.php
<?php class AppController extends Controller { use CrudControllerTrait; public $components = [ 'Crud.Crud' => [ 'actions' => ['index'], 'listeners' => [ 'Api', 'ApiPagination', 'ApiTransformation // ããï¼ ] ] ]; }
ã©ããªãããªï¼
http://localhost/geometries.json?page=2&limit=3
{
"success": true,
"data": [
{
"id": 4,
"latlng": null,
"lat": 83.012136,
"lng": 165.754295
},
{
"id": 5,
"latlng": null,
"lat": 123.59616,
"lng": 201.408059
},
{
"id": 6,
"latlng": null,
"lat": 80.112906,
"lng": 177.030496
}
],
"pagination": {
"page_count": 3334,
"current_page": 2,
"has_next_page": true,
"has_prev_page": true,
"count": 10000,
"limit": 3
}
}
ãããï¼ããæé«ï¼
ããèå¿ã®çµè¾¼æ¤ç´¢ãã£ã¦ãªãã£ãã§ããã
http://localhost/geometries.json?lat=35.67832667&lng=139.77044378
{
"success": true,
"data": [
{
"id": 2583,
"latlng": null,
"lat": 35.790109,
"lng": 140.713021
},
{
"id": 5111,
"latlng": null,
"lat": 35.759589,
"lng": 140.428571
},
{
"id": 6944,
"latlng": null,
"lat": 36.627709,
"lng": 140.225557
}
],
"pagination": {
"page_count": 1,
"current_page": 1,
"has_next_page": false,
"has_prev_page": false,
"count": 3,
"limit": 20
}
}
ã¯ãï¼è¦äºã«çµãã¦ããã¾ãï¼
æå¾ã«
Crudãã©ã°ã¤ã³ã¯ãGETã ããããªãã¦POSTãPUTãUPDATEãDELETEã«ã対å¿ãã¦ãã®ã§ã夢ãåºããã¾ããã³ã°ã§ããã
ã¨ããããªã¨ã³ããªã¼ãæ¸ãããããããªã¼ã«ãªã£ã¦æãã¦ããã¨ã³ã¸ãã¢ãããã«ããã®ã§ããªã«ããä»äºãã ããï¼
CakePHPã®å®è£ æå°ãããã©ã¼ãã³ã¹æ¹åãå®éã®ã³ã¼ãã£ã³ã°ãªã©ãªã©ããå¾ ã¡ãã¦ããã¾ããé£çµ¡å ã¯slywalker (Yasuo Harada)ã«ã¡ã¼ã«ã¢ãã¬ã¹ãè¨è¼ãã¦ããã¾ãã