PHPカンファレンス2014に参加
無差別休LT
ひよこテスト駆動開発
エンジニアなりたてでユニットテストを実行する際に苦戦した話
・データの初期化や終了時にいろいろ仕込むこと
・ドキュメントを読んでおこう
→最初からそのようなことを意識できるとエンジニアとして仕事している感じがします。
恐怖、シェルショッカー1号男
シェルスクリプトだけでDBなどを使用せずにショッピングカートを構築した話
→爆笑wwwwwww
中年以降のエンジニアの成長戦略
仕事をしていく内に技術が停滞していくことに対応するためにどうすればいいのか?
みたいなことでした
→健康に気をつけながら断捨離だそうです。
Log解析の基本?
→機械学習とか難しいと思うけど。面白いかもしれないのでやろうぜ!
PHPNGの動向
→PHPの動向、6は捨てる、7はおそらく再来年あたりにでるかも
PHPer女子が語る。こんなコードを書く人はモテない
→難しいコードじゃなくて意味不明なコードを書くとモテないよ。という話
→ちょっとワロタ
所感
今年はあまりイベントに参加出来ていない感じがうまく実感出来ている。
昨年とはまた、異なる技術が多く出てきているので技術に置いて行かれている感がある。
時間の問題もあるので多少気にしながら対応しておこう。
おまけ
体調を崩さないように健康には気を付けよう。
これからはそちらを優先にしないといけないようだし。
痛風痛かった(TдT)
cakephp3のmigrations
migrations
テーブルの設定などを行うらしい
まずは準備
新規インストール(すでにある場合は無視)
curl -s https://getcomposer.org/installer | php php composer.phar create-project --prefer-dist -s dev cakephp/app
app/composer.json
{ "name": "cakephp/app", "description": "CakePHP skeleton app", "homepage": "http://cakephp.org", "type": "project", "license": "MIT", "require": { "php": ">=5.4.16", "cakephp/cakephp": "3.0.*-dev", "mobiledetect/mobiledetectlib": "2.*", "cakephp/debug_kit": "3.0.*-dev". "cakephp/migrations": "dev-master" }, "require-dev": { "d11wtq/boris": "1.0.*" }, "suggest": { "phpunit/phpunit": "Allows automated tests to be run without system-wide install.", "cakephp/cakephp-codesniffer": "Allows to check the code against the coding standards used in CakePHP." }, "autoload": { "psr-4": { "App\\": "src" } }, "autoload-dev": { "psr-4": { "App\\Test\\": "tests", "Cake\\Test\\Fixture\\": "./vendor/cakephp/cakephp/tests/Fixture" } }, "scripts": { "post-install-cmd": "App\\Console\\Installer::postInstall" }, "config" : { "bin-dir" : "bin" }, "minimum-stability" : "dev", "prefer-stable": true }
※"cakephp/migrations"を追加
update
cd app php ../composer.phar update cakephp/migrations
確認
$ sh app/bin/cake migrations Welcome to CakePHP v3.0.0-beta2 Console --------------------------------------------------------------- App : src Path: /vagrant/projects/beta2/app/src/ --------------------------------------------------------------- Migrations plugin, based on Phinx by Rob Morgan. version 0.3.5 Usage: [options] command [arguments] Options: --help -h Display this help message. --quiet -q Do not output any message. --verbose -v|vv|vvv Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug --version -V Display this application version. --ansi Force ANSI output. --no-ansi Disable ANSI output. --no-interaction -n Do not ask any interactive question. Available commands: create Create a new migration help Displays help for a command list Lists commands migrate Migrate the database rollback Rollback the last or to a specific migration status Show migration status $
※動くかもしれない…
初期化
sh app/bin/cake migrations create Initial
↓
$ sh app/bin/cake migrations create Initial Welcome to CakePHP v3.0.0-beta2 Console --------------------------------------------------------------- App : src Path: /vagrant/projects/beta2/app/src/ --------------------------------------------------------------- using migration path /vagrant/projects/beta2/app/config/Migrations created ./app/config/Migrations/20141007152249_initial.php $
app/config/Migrations/20141007152249_initial.php
<?php use Phinx\Migration\AbstractMigration; class Initial extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * * Uncomment this method if you would like to use it. * public function change() { } */ /** * Migrate Up. */ public function up() { } /** * Migrate Down. */ public function down() { } }
※初期データなのでこれだけ…
up時のメソッドを追加
<?php use Phinx\Migration\AbstractMigration; class Initial extends AbstractMigration { /** * Change Method. * * More information on this method is available here: * http://docs.phinx.org/en/latest/migrations.html#the-change-method * * Uncomment this method if you would like to use it. * public function change() { } */ /** * Migrate Up. */ public function up() { $_table = "sample1"; if($this->hasTable($_table)){ $this->dropTable("sample1"); } $sample1 = $this->table("sample1" , array( "id" => false, "primary_key" => array("id") ) ); $sample1 ->addColumn("id", "integer") ->addColumn("name", "string", array("limit" => 50)) ->addColumn("created", "datetime") ->addColumn("updated", "datetime") ->create(); } /** * Migrate Down. */ public function down() { } }
実行してみる
$ sh app/bin/cake migrations migrate Welcome to CakePHP v3.0.0-beta2 Console --------------------------------------------------------------- App : src Path: /vagrant/projects/beta2/app/src/ --------------------------------------------------------------- using migration path /vagrant/projects/beta2/app/config/Migrations using environment default using adapter mysql using database my_app All Done. Took 0.0147s $
できたもの
管理テーブルとして
phinxlog
というテーブルで更新情報を管理しているよう
所感
データベースの定義もソースで管理できるようになった。
SQLなどを別途設計書を用意するよりは多少楽かもしれない。
まだ、いろいろと制約があるか確認することはありそうですけど…
再作成などは便利になりそう。
cakephp3のbeta2が出たらしく見てみた
最近は触っていなかった
見てみたらなんかもうbeta2まで上がっているらしいので見てみる。
githubではなんかまだ、よくわからない…
issueが多すぎるw
インストール
以下参照
mkdir beta2 cd beta2 curl -s https://getcomposer.org/installer | php php composer.phar create-project --prefer-dist -s dev cakephp/app
起動
app/binから起動
sh app/bin/cake server -H 192.168.33.10 -p 1234
画面
※めちゃくちゃ変わっている???
debugkitが下に移動している
※頭にあって邪魔と思った場合もあるしこれはいいかも
bake
postsを用意
sh app/bin/cake bake controller posts sh app/bin/cake bake model posts sh app/bin/cake bake view posts
画面
まとめ
debugkitも出てきたので基本的な機能はほぼ完成しているということなのかもしれません。
モデルの使い方はまだ良くわかっていないけど今までのような配列地獄から脱出できるようなので
小規模なwebアプリならなんかできるかも…
cakephp2.5系のブログチュートリアル+Twigテンプレート組み込み
最近は3系の検証ばかり
日本語のマニュアルもあるので多少わかりやすくなっているけど簡単なアプリはどんな感じか確認
インストール
clone
mkdir cakephp2.5.x git clone https://github.com/cakephp/cakephp.git -b 2.5.3 cd cakephp/ git submodule add https://github.com/cakephp/debug_kit.git app/Plugin/DebugKit
core.php
<?php /** * A random string used in security hashing methods. */ Configure::write('Security.salt', 'なんか適当に'); /** * A random numeric string (digits only) used to encrypt/decrypt strings. */ Configure::write('Security.cipherSeed', 'なんか適当に');
※認証情報を隠蔽する
database.php
<?php class DATABASE_CONFIG { public $default = array( 'datasource' => 'Database/Mysql', 'persistent' => false, 'host' => 'localhost', 'login' => 'ユーザーid', 'password' => 'パスワード', 'database' => '使用するデータベース名', 'prefix' => '', //'encoding' => 'utf8', ); }
※適当にデータベースを用意して接続情報を設定
AppController.php
<?php class AppController extends Controller { public $components = array('DebugKit.Toolbar'); }
※DebugKit.Toolbarのコンポーネントを取り込み
起動
sh app/Console/cake server -H 192.168.33.10 -p 1234
※簡易コマンドで起動
サンプル作成
posts
CREATE TABLE posts ( id INT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT, title VARCHAR(50), body LONGTEXT, created DATETIME DEFAULT CURRENT_TIMESTAMP, modified DATETIME );
bake
sh app/Console/cake bake controller posts sh app/Console/cake bake model posts sh app/Console/cake bake view posts
再起動して確認
テンプレート切り替え
プラグインインストール
git submodule add git://github.com/predominant/TwigView.git app/Plugin/TwigView cd app/Plugin/TwigView git submodule update --init
※twigのライブラリもダウンロードする
使用するViewを変更
<?php App::uses('Controller', 'Controller'); class AppController extends Controller { public $components = array( 'DebugKit.Toolbar', 'Session', ); public $viewClass = 'TwigView.Twig'; public $ext = '.twig'; public $helpers = array('Html', 'Form'); public function beforeFilter() { parent::beforeFilter(); } }
※ここでtwigファイルの拡張子を指定する
PostsControllerを修正
<?php App::uses('AppController', 'Controller'); /** * Posts Controller * */ class PostsController extends AppController { /** * Scaffold * * @var mixed */ public function index(){ $this->paginate = array( 'limit'=>10 ); $this->set('posts', $this->Post->find('all')); } public function view($id) { if (!$id) { throw new NotFoundException(__('Invalid post')); } $post = $this->Post->findById($id); if (!$post) { throw new NotFoundException(__('Invalid post')); } $this->set('post', $post); } public function add() { if ($this->request->is('post')) { if ($this->Post->save($this->request->data)) { $this->Session->setFlash(__('Your post has been saved.')); return $this->redirect(array('action' => 'index')); } $this->Session->setFlash(__('Unable to add your post.')); } } public function edit($id = null) { if (!$id) { throw new NotFoundException(__('Invalid post')); } $post = $this->Post->findById($id); if (!$post) { throw new NotFoundException(__('Invalid post')); } if ($this->request->is(array('post', 'put'))) { $this->Post->id = $id; if ($this->Post->save($this->request->data)) { $this->Session->setFlash(__('Your post has been updated.')); return $this->redirect(array('action' => 'index')); } $this->Session->setFlash(__('Unable to update your post.')); } if (!$this->request->data) { $this->request->data = $post; } } public function delete($id) { if ($this->request->is('get')) { throw new MethodNotAllowedException(); } if ($this->Post->delete($id)) { $this->Session->setFlash(__('The post with id: %s has been deleted.', h($id))); return $this->redirect(array('action' => 'index')); } } }
※bakeで作成していたのですが手動で作成しなおし
※Scaffoldingを使用した場合は暫定のViewなどを使用するのでカスタムテンプレートを使用できない
各テンプレートを修正
phpでの記法があるけどテンプレートでは使用できない場合は手動で書き直し
index.twig
<div class="posts index"> <h2>Posts</h2> <table cellpadding="0" cellspacing="0"> <tbody> {% for post in posts %} <tr> <td>{{ post.Post.id }}</td> <td>{{ post.Post.title }}</td> <td>{{ post.Post.body }}</td> <td>{{ post.Post.created }}</td> <td>{{ post.Post.modified }}</td> <td class="actions"> {{ html.link('View', {'controller': 'posts', 'action': 'view/'~post.Post.id}) }} {{ html.link('Edit', {'controller': 'posts', 'action': 'edit/'~post.Post.id}) }} {{ form.postLink( 'Delete', { 'action': 'delete/'~post.Post.id }, 'Delete' ) }} </td> </tr> {% endfor %} </tbody> </table> </div> <div class="actions"> <h3>Action</h3> <ul> <li> {{ html.link('New Post', {'action': 'add'}) }} </li> </ul> </div>
add.twig
<div class="posts form"> {{ form.create('Post') }} <fieldset> <legend>Add Post</legend> {{ form.input('title') }} {{ form.input('body') }} </fieldset> {{ form.end('Submit') }} </div> <div class="actions"> <h3>Actions</h3> <ul> <li> {{ httml.link('List Posts', {'action': 'index'}) }} </li> </ul> </div>
view.twig
<div class="posts view"> <h2>Post</h2> <dl> <dt>Id</dt> <dd> {{ post.Post.id }}) </dd> <dt>Title</dt> <dd> {{ post.Post.title }} </dd> <dt>Body</dt> <dd> {{ post.Post.body }} </dd> <dt>Created</dt> <dd> {{ post.Post.created }} </dd> <dt>Modified</dt> <dd> {{ post.Post.modified }} </dd> </dl> </div> <div class="actions"> <h3>Actions</h3> <ul> <li>{{ html.link('Edit Post', {'action': 'edit/'~post.Post.id}) }}</li> <li>{{ form.postLink('Delete Post', {'action': 'delete/'~post.Post.id}, 'Delete') }}</li> <li>{{ html.link('List Posts', {'action': 'index'}) }}</li> <li>{{ html.link('New Post', {'action': 'add'}) }}</li> </ul> </div>
edit.twig
<div class="posts form"> {{ form.create('Post') }} <fieldset> <legend>Edit Post</legend> {{ form.input('id') }} {{ form.input('title') }} {{ form.input('body') }} </fieldset> {{ form.end('Submit') }} </div> <div class="actions"> <h3>Actions</h3> <ul> <li>{{ form.postLink('Delete', {'action': 'delete/'~form.value('Post.id')}, 'Delete') }}</li> <li>{{ html.link('List Posts', {'action': 'index'}) }}</li> </ul> </div>
まとめ
以前使用していたのは2.3までなのでいくつかの機能は変わっている感じはする。
今回、簡単にtwigを使用してみたけどいろいろ面倒な感じはした。(´・ω・`)
<?php $cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework'); $cakeVersion = __d('cake_dev', 'CakePHP %s', Configure::version()) ?>
こんな感じの__d関数などを使用することができなかったりといくつかの不便な感じはした。
まあ、そのあたりはコントローラーやモデルなどで対応していくことで対応出来そう。
ヘルパー機能は使わないほうが吉な感じです。
cssやスクリプトをどうしても読み込みたい場合などは使用する必要がありそうですけど…
phpテンプレートtwigの確認
インストール
composerでインストール
mkdir twig_sample cd twig_sample/ curl -s http://getcomposer.org/installer | php cat << _EOT_ > composer.json { "require": { "twig/twig": "1.*" } } _EOT_ php composer.phar install
シンプルな使い方
templates/sample.twig
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {{ hoge }} </body> </html>
※テンプレートを用意
test1.php
<?php /** */ require_once __DIR__ . "/vendor/autoload.php"; // 初期化 Twig_Autoloader::register(); // 設定 $loader = new Twig_Loader_Filesystem(__DIR__ . '/templates'); $twig = new Twig_Environment($loader); // テンプレートを使用 $template = $twig->loadTemplate("sample.twig"); // レンダリング echo $template->render([ "hoge" => "Hello World." ]);
↓
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> Hello World. </body> </html>
こうなる
指定方法ざっくり
通常のスカラー変数
<?php require_once __DIR__ . "/vendor/autoload.php"; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem(__DIR__ . '/templates'); $twig = new Twig_Environment($loader); $template = $twig->loadTemplate("sample.twig"); // 値を設定 $aaa = "111"; echo $template->render([ "hoge" => $aaa ]);
の場合はrenderで指定したキー名をそのまま指定するだけ
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {{ hoge }} </body> </html>
配列の場合
<?php require_once __DIR__ . "/vendor/autoload.php"; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem(__DIR__ . '/templates'); $twig = new Twig_Environment($loader); $template = $twig->loadTemplate("sample.twig"); // 値を設定 $aaa = ["111" => "aaa"]; echo $template->render([ "hoge" => $aaa ]);
配列の場合はsmartyの場合と同様"."を連結する方法と、キーを指定する方法の2つが利用できる
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {{ hoge['111'] }} {{ hoge.111 }} </body> </html>
オブジェクト
<?php require_once __DIR__ . "/vendor/autoload.php"; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem(__DIR__ . '/templates'); $twig = new Twig_Environment($loader); $template = $twig->loadTemplate("sample.twig"); // 値を設定 $aaa = new stdClass(); $aaa->hoge = 100; $aaa->foo = 200; echo $template->render([ "hoge" => $aaa ]);
オブジェクトの場合も"."でアクセスできる
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {{ hoge.hoge }} {{ hoge.foo }} </body> </html>
if、foreach
<?php require_once __DIR__ . "/vendor/autoload.php"; Twig_Autoloader::register(); $loader = new Twig_Loader_Filesystem(__DIR__ . '/templates'); $twig = new Twig_Environment($loader); $template = $twig->loadTemplate("sample.twig"); // 値を設定 $aaa = [ 0 => 100, 1 => 200, 2 => 300, ]; echo $template->render([ "hoge" => $aaa ]);
if文やforeachなどは%を指定して制御
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {% if hoge|length > 0 %} <ul> {% for item in hoge %} <li>{{ item }}</li> {% endfor %} </ul> {% endif %} </body> </html>
内部で変数を動的に作成
set文を使用することで可能
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {% set aaa = 100 %} <div> {{ aaa }} </div> {% set list = [ 100, 200, 300 ] %} <ul> {% for item in list %} <li>{{ item }}</li> {% endfor %} </ul> </body> </html>
文字列の連結
php側でレンダリングした変数とhtmlの値を連結することも可能
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {% set aaa = "aaa"~hoge %} </body> </html>
別のテンプレートをインクルード
sample.twig
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {% include "sample2.twig" %} </body> </html>
sample2.twig
<h1>Hello World</h1> {{ hoge }}
↓
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> <h1>Hello World</h1> hoge</body> </html>
おまけ
エスケープ確認
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {% set foo = "<h1>hello world.</h1>" %} {{ foo }} </body> </html>
↓
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> <h1>hello world.</h1> </body> </html>
htmlエスケープを無効にしたい場合
<!DOCType html> <html> <head> <meta charset="utf8" /> </head> <body> {% set foo = "<h1>hello world.</h1>" %} {{ foo|raw }} </body> </html>
※フィルタにrawを使用する
今回はここまで…
Laravel4のチュートリアル2
最初からやり直し
これ見たけどなんかlaravelで簡単にできそうだけどどんな中身かわからなかったので…
手順
composerをインストール
mkdir laravel1 cd laravel1 curl -sS https://getcomposer.org/installer | php php composer.phar create-project laravel/laravel app1
※結構インストールするものがあるから時間がかかる
データベースを作成
mysql -uroot -e "create database laravel_db;";
設定
app/config/database.php
'mysql' => array( 'driver' => 'mysql', 'host' => 'localhost', 'database' => 'laravel_db', 'username' => 'root', 'password' => '', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ),
※デフォルトでmysqlなのでその部分を変更
バージョンを確認
[vagrant@localhost app1]$ php artisan --version Laravel Framework version 4.2.6 [vagrant@localhost app1]$
確認
[vagrant@localhost app1]$ php artisan serve --host=192.168.33.10 Laravel development server started on http://192.168.33.10:8000
ジェネレータ導入
composer.jsonに追加
"require-dev": { "way/generators": "2.*" }
update
php ../composer.phar update
コマンド確認
generate generate:controller Generate a controller generate:migration Generate a new migration generate:model Generate a model generate:pivot Generate a pivot table generate:publish-templates Copy generator templates for user modification generate:resource Generate a new resource generate:scaffold Scaffold a new resource (with boilerplate) generate:seed Generate a database table seeder generate:view Generate a view key key:generate Set the application key migrate migrate:install Create the migration repository migrate:make Create a new migration file migrate:publish Publish a package's migrations to the application migrate:refresh Reset and re-run all migrations migrate:reset Rollback all database migrations migrate:rollback Rollback the last database migration
雛形作成
[vagrant@localhost app1]$ php artisan generate:scaffold post --fields="title:string, body:text" Do you want me to create a Post model? [yes|no] Created: /vagrant/laravel1/app1/app/models/Post.php Do you want me to create views for this Post resource? [yes|no] Created: /vagrant/laravel1/app1/app/views/posts/index.blade.php Created: /vagrant/laravel1/app1/app/views/posts/show.blade.php Created: /vagrant/laravel1/app1/app/views/posts/create.blade.php Created: /vagrant/laravel1/app1/app/views/posts/edit.blade.php Do you want me to create a PostsController controller? [yes|no] Created: /vagrant/laravel1/app1/app/controllers/PostsController.php Do you want me to create a 'create_posts_table' migration and schema for this resource? [yes|no] Created: /vagrant/laravel1/app1/app/database/migrations/2014_07_18_072514_create_posts_table.php Generating optimized class loader Compiling common classes Compiling views Would you like a 'Posts' table seeder? [yes|no] Created: /vagrant/laravel1/app1/app/database/seeds/PostsTableSeeder.php Do you want to go ahead and migrate the database? [yes|no] ************************************** * Application In Production! * ************************************** Do you really wish to run this command? Migrated: 2014_07_18_072514_create_posts_table Done! All done! Don't forget to add 'Route::resource('posts', 'PostsController');` to app/routes.php. [vagrant@localhost app1]$
app/routes.php
<?php /* |-------------------------------------------------------------------------- | Application Routes |-------------------------------------------------------------------------- | | Here is where you can register all of the routes for an application. | It's a breeze. Simply tell Laravel the URIs it should respond to | and give it the Closure to execute when that URI is requested. | */ Route::get('/', function() { return View::make('hello'); }); Route::resource('posts', 'PostsController');
app/controllers/PostsController.php
<?php class PostsController extends \BaseController { /** * Display a listing of posts * * @return Response */ public function index() { $posts = Post::all(); return View::make('posts.index', compact('posts')); } /** * Show the form for creating a new post * * @return Response */ public function create() { return View::make('posts.create'); } /** * Store a newly created post in storage. * * @return Response */ public function store() { $validator = Validator::make($data = Input::all(), Post::$rules); if ($validator->fails()) { return Redirect::back()->withErrors($validator)->withInput(); } Post::create($data); return Redirect::route('posts.index'); } /** * Display the specified post. * * @param int $id * @return Response */ public function show($id) { $post = Post::findOrFail($id); return View::make('posts.show', compact('post')); } /** * Show the form for editing the specified post. * * @param int $id * @return Response */ public function edit($id) { $post = Post::find($id); return View::make('posts.edit', compact('post')); } /** * Update the specified post in storage. * * @param int $id * @return Response */ public function update($id) { $post = Post::findOrFail($id); $validator = Validator::make($data = Input::all(), Post::$rules); if ($validator->fails()) { return Redirect::back()->withErrors($validator)->withInput(); } $post->update($data); return Redirect::route('posts.index'); } /** * Remove the specified post from storage. * * @param int $id * @return Response */ public function destroy($id) { Post::destroy($id); return Redirect::route('posts.index'); } }
※これはそのまま
app/models/Post.php
<?php class Post extends \Eloquent { // Add your validation rules here public static $rules = [ // 'title' => 'required' ]; // Don't forget to fill this array protected $fillable = []; }
※これはそのまま
app/views/posts/index.blade.php
/vagrant/laravel1/app1/app/views/posts/index.blade.php
※は???
↓へ修正
<!DOCType html> <html> <head> <title>post test</title> </head> <body> <h1>post test</h1> <table border="1"> @foreach ($posts as $post) <tr> <td>{{{ $post->id }}}</td> <td>{{{ $post->title }}}</td> <td>{{{ $post->body }}}</td> <td>{{{ $post->created_at }}}</td> </tr> @endforeach </table> </body> </html>
↓確認
cakephp3【alpha1】クエリービルダー2
クエリービルダーでちょびっとネスト
(id = :c0 AND id = :c1 AND (aaa IN (:c2,:c3) OR bbb >= :c4) AND xxx != :c5 AND NOT ((vvv = :c6 AND yyy = :c7)) AND hhh LIKE :c8)
=やIN、OR、ANDなどをごちゃごちゃに組み込むとこんな感じ
↓
サンプル
<?php namespace App\Console\Command; use Cake\Console\Shell; use Cake\ORM\TableRegistry; /** * Sample4 shell command. */ class Sample4Shell extends Shell { /** * main() method. * * @return bool|int Success or error code. */ public function main() { $members = TableRegistry::get('Members'); $query = $members->query(); var_dump( $query->select()->where(function($exp) { $conditions = $exp->and_(function($_and){ return $_and ->eq('id', 10) ->eq('id', 20) ->add($_and->or_(function($_or){ return $_or ->in('aaa', [10, 20]) ->gte('bbb', 20) ; })) ->notEq('xxx', 20) ->not($_and->and_(function($_and){ return $_and ->eq('vvv', 10) ->eq('yyy', 30) ; })) ->like('hhh', '%sss%') ; }); return $conditions; })->sql() ); } }
↓
SELECT Members.id AS `Members__id`, Members.name AS `Members__name`, Members.age AS `Members__age`, Members.tel AS `Members__tel`, Members.created AS `Members__created`, Members.modified AS `Members__modified` FROM members AS Members WHERE ( id = :c0 AND id = :c1 AND ( aaa IN (:c2,:c3) OR bbb >= :c4 ) AND xxx != :c5 AND NOT ( (vvv = :c6 AND yyy = :c7) ) AND hhh LIKE :c8)
メソッド
- and_、or_
これらは内部に条件を指定して、内部で指定した条件をandまたはorで連結するもの
- eq、in、likeなど
and_、or_の中で指定する条件で項目との値のチェックに使用
- not
and_や or_を括るときに使用し、その際、その中野条件をNOTで挟む
確認
以下のデータ
mysql> select * from members; +----+--------------------------+------+--------+---------+--------------+---------------------+---------------------+ | id | name | age | status | deleted | tel | created | modified | +----+--------------------------+------+--------+---------+--------------+---------------------+---------------------+ | 1 | テスとユーザー1 | 20 | 0 | 0 | 000-111-2222 | 2014-06-07 21:37:25 | 2014-06-07 21:37:25 | | 2 | テスとユーザー2 | 18 | 0 | 0 | 0001112222 | 2014-06-07 21:38:24 | 2014-06-07 21:38:24 | | 3 | テスとユーザー3 | 18 | 0 | 0 | 0001113333 | 2014-06-07 21:41:48 | 2014-06-07 21:41:48 | +----+--------------------------+------+--------+---------+--------------+---------------------+---------------------+ 3 rows in set (0.00 sec) mysql>
php
<?php namespace App\Console\Command; use Cake\Console\Shell; use Cake\ORM\TableRegistry; /** * Sample4 shell command. */ class Sample4Shell extends Shell { /** * main() method. * * @return bool|int Success or error code. */ public function main() { $members = TableRegistry::get('Members'); $query = $members->find(); $list = $query->select()->where(function($exp) { $conditions = $exp->and_(function($_and){ return $_and ->eq('deleted', 0) ->add($_and->or_(function($_or){ return $_or ->in('age', [20, 18]) ->gte('age', 20) ; })) ->notEq('deleted', 1) ->not($_and->and_(function($_and){ return $_and ->eq('status', 0) ->eq('tel', '000-111-2222') ; })) ->like('name', 'テス%') ; }); return $conditions; } ); var_dump($list->sql()); foreach($list as $item){ var_dump( $item->id, $item->name, $item->age, $item->tel, $item->status, $item->created->__toString(), $item->modified->__toString() ); echo "----\n"; } } }
結果
[vagrant@localhost alpha1]$ sh app/src/Console/cake sample4 Welcome to CakePHP v3.0.0-alpha1 Console --------------------------------------------------------------- App : src Path: /vagrant/projects/alpha1/app/src/ --------------------------------------------------------------- string(444) "SELECT Members.id AS `Members__id`, Members.name AS `Members__name`, Members.age AS `Members__age`, Members.status AS `Members__status`, Members.deleted AS `Members__deleted`, Members.tel AS `Members__tel`, Members.created AS `Members__created`, Members.modified AS `Members__modified` FROM members AS Members WHERE (deleted = :c0 AND (age IN (:c1,:c2) OR age >= :c3) AND deleted != :c4 AND NOT ((status = :c5 AND tel = :c6)) AND name LIKE :c7)" int(2) string(24) "テスとユーザー2" int(18) string(10) "0001112222" int(0) string(14) "6/7/14 9:38 PM" string(14) "6/7/14 9:38 PM" ---- int(3) string(24) "テスとユーザー3" int(18) string(10) "0001113333" int(0) string(14) "6/7/14 9:41 PM" string(14) "6/7/14 9:41 PM" ---- [vagrant@localhost alpha1]$
まあ、それっぽく出ている感じ。
複数のテーブルを使用する際にどうするか?
SEELECT * FROM users left outer join ( SELECT id FROM members WHERE group = 10 ) AS T1 ON T1.id = users.id
こんなこととかいろいろ調べないといけない
まとめ
クエリービルダーでネストを使用して条件を複雑に指定できるようです。
likeの場合は%を条件として使うか、値として使うかが別れる場合があるのでちょっと気をつける必要がある。