m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

PHPカンファレンス2014に参加

概要

PHPカンファレンス2014
phpのあれこれの情報が聞けました。

日時

2014/10/11(土) 10:00~17:00くらい

金額

無料

ハッシュタグ

#phpcon2014

f:id:m_shige1979:20141011093613j:plain

参加したもの

基調講演

PHPの現状の情報、php5.3が多いけどこれから5.4も増えてくるかも。
php6はキャンセルしてphp7を準備中

サイトの調査に使えるかも

Sites Info

Ansibleで始めるサーバ作業の自動化

クライアントからサーバへの自動化を行うツール
pythonで動くのでunix系のクライアントでないと動かない
windowsは無理

mysqlnd徹底解説

libmysql→mysqlndにその内変化するので気にしておこう

PHPerがAWSと出会ってDevOpsを目指した話

開発するだけでなく、AWSなどでサーバの構成などを意識できるようにすることが今後必要

PHPにおけるI/O多重化とyield

yieldイマイチわからん

HHVM + Hack == PHP++

HHVM速い。
フレームワークへの対応中

HHVM


centosはバイナリがない(TдT)
ubuntuを使えということなのか

Webアプリのデプロイ今昔物語

FTPwinSCPしかつかっていないのですがAWSとかはまだ、
デプロイツールを使わないといけないようです。
楽するために手間がかかるということ



無差別休LT

PHP + 伺たなんとかで始まる新しいPHPの形

通知アプリを作ってさくらさんを喋らせる、機能を実装の説明
→さくらさん可愛かったです。

ひよこテスト駆動開発

エンジニアなりたてでユニットテストを実行する際に苦戦した話
・データの初期化や終了時にいろいろ仕込むこと
・ドキュメントを読んでおこう
→最初からそのようなことを意識できるとエンジニアとして仕事している感じがします。

恐怖、シェルショッカー1号男

シェルスクリプトだけでDBなどを使用せずにショッピングカートを構築した話
→爆笑wwwwwww

中年以降のエンジニアの成長戦略

仕事をしていく内に技術が停滞していくことに対応するためにどうすればいいのか?
みたいなことでした
→健康に気をつけながら断捨離だそうです。

Slow Queryとの戦い(ORM)

→ORMを使用するとSQLが見えないのでSQLの構成により時間がかかるクエリーになると思うのでSQLになることを意識しよう

Log解析の基本?

機械学習とか難しいと思うけど。面白いかもしれないのでやろうぜ!

PHPNGの動向

PHPの動向、6は捨てる、7はおそらく再来年あたりにでるかも

PHPer女子が語る。こんなコードを書く人はモテない

→難しいコードじゃなくて意味不明なコードを書くとモテないよ。という話
→ちょっとワロタ

良いことも悪いことも全部PHPが教えてくれた

PHPを始めることで便利なことや不便なことがあったことを理解できたということ

PHPでAIプログラミングで準優勝するまでの軌跡

→AIプログラミングにPHPは向かないよw


f:id:m_shige1979:20141011163800j:plain

所感

今年はあまりイベントに参加出来ていない感じがうまく実感出来ている。
昨年とはまた、異なる技術が多く出てきているので技術に置いて行かれている感がある。
時間の問題もあるので多少気にしながら対応しておこう。

おまけ

体調を崩さないように健康には気を付けよう。
これからはそちらを優先にしないといけないようだし。
痛風痛かった(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
app/config/bootstrap.phpプラグインに追加
Plugin::load('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
$
できたもの

f:id:m_shige1979:20141008010523p:plain

管理テーブルとして

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
画面

f:id:m_shige1979:20141004052822p:plain
※めちゃくちゃ変わっている???

debugkitが下に移動している

f:id:m_shige1979:20141004053247p:plain
※頭にあって邪魔と思った場合もあるしこれはいいかも

bake

postsを用意
sh app/bin/cake bake controller posts
sh app/bin/cake bake model posts
sh app/bin/cake bake view posts
画面

f:id:m_shige1979:20141004054212p:plain

まとめ

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',
	);
} 

※適当にデータベースを用意して接続情報を設定

bootstrap.php
<?php
CakePlugin::loadAll();
CakePlugin::load('DebugKit');

※debugkit取り込み

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

※簡易コマンドで起動

f:id:m_shige1979:20140726094218p:plain

サンプル作成

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
再起動して確認

f:id:m_shige1979:20140726095750p:plain
f:id:m_shige1979:20140726095800p:plain
f:id:m_shige1979:20140726095811p:plain
f:id:m_shige1979:20140726095824p:plain

テンプレート切り替え

プラグインインストール
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ファイルの拡張子を指定する

bootstrap.phpプラグインを追加
<?php

いろいろ…

CakePlugin::load('TwigView');

いろいろ…

※追加

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 }})
			&nbsp;
		</dd>
		<dt>Title</dt>
		<dd>
			{{ post.Post.title }}
			&nbsp;
		</dd>
		<dt>Body</dt>
		<dd>
			{{ post.Post.body }}
			&nbsp;
		</dd>
		<dt>Created</dt>
		<dd>
			{{ post.Post.created }}
			&nbsp;
		</dd>
		<dt>Modified</dt>
		<dd>
		    {{ post.Post.modified }}
			&nbsp;
		</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の確認

smartyばっかり

使っていたの、cakephpだとphpで他のフレームワークをあまり触らなかったせいもあるので勉強

インストール

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>
        &lt;h1&gt;hello world.&lt;/h1&gt;
</body>
</html>
htmlエスケープを無効にしたい場合
<!DOCType html>
<html>
<head>
    <meta charset="utf8" />
</head>
<body>
    {% set foo = "<h1>hello world.</h1>" %}
    {{ foo|raw }}
</body>
</html>

※フィルタにrawを使用する

今回はここまで…

まとめ

フレームワークを使用する場合は大抵、独自のテンプレートか有名ドコロのテンプレートを使用する風にしたほうが開発は捗るのでいくつか勉強しておいたほうがよい。なくてもそんなには困らないけどエスケープとかいろいろhtmlに組み込むのが嫌な感じとかあることが多いと思われる。
さずがにsmartyだけではこれから困るだろうから勉強しておかなくては…

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/app.php
	'timezone' => 'Asia/tokyo',

※timezoneをUTC→Asia/Tokyoへ

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

f:id:m_shige1979:20140718060129p:plain

ジェネレータ導入

composer.jsonに追加
    "require-dev": {
        "way/generators": "2.*"
    }
update
php ../composer.phar update
app/config/app.php
        'Way\Generators\GeneratorsServiceProvider',

※providersに追加

コマンド確認
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>

↓確認

f:id:m_shige1979:20140718073942p:plain

まとめてないけどまとめ

マイグレーションが便利かどうかはともかく取りあえず動く感じにはできる。
フレームワークなどを見ると全体の構成に惑わされて難しそうに意識して時間がかかっている感じがするので
もう少しシンプルに考えてみることが必要と思う。

いろいろな機能をどうするかではなくとりあえず動くものを作ってから調整していこう。

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の場合は%を条件として使うか、値として使うかが別れる場合があるのでちょっと気をつける必要がある。

所感

頭が悪いのでこの程度のことを調べるのにも数時間かかってしまう(´・ω・`)
今まであまり勉強してこなかったツケが帰ってきたじ感じ。

ただ、家などで怠けていたときよりもなんか1日の時間を有効に使用している感じがする。
この知識が役に立つかは不明ですがソースコードがなんか読みやすくなった気がするのでちょっとだけ楽しいかもしれない。