slimでpimpleを使ってデータベースに接続

pimpleを使ってデータベースへの接続を行いデータベースからデータを取ってくるようにします。

データベースにテーブルとデータを追加

MYSQLのhogeデータベースにユーザ「hoge」パスワード「hogepass」で接続できるように設定してます。

create databases hoge;
GRANT ALL PRIVILEGES ON hoge.* TO hoge@localhost IDENTIFIED BY 'hogepass';
flush privileges;
mysql> use hoge
mysql> create table user (name varchar(10));
mysql> insert into user (name)values('taka512');

dbに接続するクラスを作成

PDOを利用してMYSQLに接続するクラスです。

$ mkdir src/Taka512/Db
$ vi src/Taka512/Db/Mysql.php
<?php
namespace Taka512\Db;
class Mysql
{
    protected static $conn = null;
    public static function connect($host, $database, $user, $password)
    {
        if (self::$conn == null) {
            try {
                self::$conn = new \PDO(
                    sprintf('mysql:host=%s;dbname=%s;charset=utf8', $host, $database),
                    $user,
                    $password,
                    array(\PDO::ATTR_EMULATE_PREPARES => false)
                );
            } catch (\PDOException $e) {
                echo 'Connection failed: ' . $e->getMessage();
                die;
            }
        }
        return self::$conn;
    }
}

dbからデータを取得処理を作成

今までgetNameは固定文字列を返してましたがデータベースからデータを取得するように修正

$ vi src/Taka512/Services/NameService.php
class NameService
{
~省略~
    public function getName()
    {
        $name = null;
        try {
            $stmt = $this->di['db_master']->query("SELECT name FROM user");

            while($row = $stmt->fetch(\PDO::FETCH_ASSOC)){
                $name =  $row['name'];
            }
        } catch (\PDOException $e){
            var_dump($e->getMessage());
            die;
        }
        return $name;

index.phpの修正
pimpleにデータベースへの接続処理を追加します。

$ vi web/index.php
~省略~
$container = new Pimple();
$container['app'] = $app;

$container['db_master'] = $container->share(function($c){
       return \Taka512\Db\Mysql::connect(
            'localhost'/*host*/,
            'hoge'/*database*/,
            'hoge'/*id*/,
            'hogepass'/*pass*/);
        });

こんな感じでデータベースへの接続処理を追加できます。

slimでpimpleを使ってroutingを行う

pimpleを使ってslimのroutingを構造化してみます。

routes.phpの作成

configディレクトリを作成し、routing情報を記述するroutes.phpを作成します。

$ mkdir config
$ vi config/routes.php
<?php

$app->get('/', function() use ($container) {
    $container['ContentsController']->top();
  });

ContentsControllerクラスの作成

index.phpのcontrollerの中に記述していた処理をContentsControllerクラスとして独立させます。
topメソッドの中にcontroller処理を記述してます。

$ mkdir src/Taka512/Controllers
$ vi src/Taka512/Controllers/ContentsController.php
<?php

namespace Taka512\Controllers;

class ContentsController
{
    protected $app;
    protected $service;

    public function __construct(\Pimple $di) {
        $this->app = $di['app'];
        $this->init($di);
    }

    public function init(\Pimple $di) {
        $this->service = $di['NameService'];
    }

    public function top() {
        $name = $this->service->getName();
        $this->app->render('index.html.twig', array('name' => $name));
    }
}

index.phpを修正

controller処理を削除してroutes.phpの読み込み処理を追加します。

$ vi web/index.php
  9 define('PROJECT_DIR', dirname(__FILE__) . '/..');
 10 $app = new Slim(array(
 ~略~
 20 $container = new Pimple();
 21 $container['app'] = $app;
 22 $container['NameService'] = $container->share(function ($container) {
 23     return new \Taka512\Services\NameService($container);
 24 });
 25
 26 $container['ContentsController'] = $container->share(function ($container) {
 27     return new \Taka512\Controllers\ContentsController($container);
 28 });
 29
 30 require PROJECT_DIR.'/config/routes.php';
 31
 32 $app->run();

これでroutes.phpにrouting情報を定義してControllerクラスをモリモリ書いていけるようになりました。
今回の作業をした後のディレクトリ構造は下記となります。

|-- composer.json
|-- composer.lock
|-- logs
|    |-- 2013-06-29.log
|-- templates
|    |-- index.html.twig
|-- config
|    |-- routes.php
|-- vendor
|-- web
|    |-- index.php
|-- src
|    |-- Taka512
|         |-- Controllers
|              |-- ContentsController.php
|         |-- Services
|              |-- NameService.php

参考

http://nesbot.com/2012/11/5/lazy-loading-slim-controllers-using-pimple

slimでネームスペースを利用するように修正

プロジェクトディレクトリの構造化を行っていきます。
今回は前回index.phpに作成したNameServiceクラスをファイルから分離して、ネームスペースを利用するように修正します。

composer.jsonの修正

autoloadの項目を追加します。srcが設定ディレクトリで「Taka512」ネームスペースとなります。

$ vi composer.json
    "require": {
        "slim/slim": "2.*",
        "slim/extras": "2.0.*",
        "twig/twig": "1.*",
        "pimple/pimple": "1.0.0"
    },
    "autoload": {
        "psr-0": { "Taka512": "src/"}
    }
$ php composer.phar update

ディレクトリの作成

先ほどautoloadで設定したディレクトリを作成します。

$ mkdir -p src/Taka512/Services

NameServiceライブラリの作成

NameServiceクラスをファイルに分離します。今回の例ではネームスペースは「Taka512\Services」となります。
constructのPimpleの前に「\」マークをつけるのを忘れないようにしましょう。つけないと「Taka512\Service\Pimple」を探しに行ってエラーとなります。

$ vi src/Taka512/Services/NameService.php
<?php

namespace Taka512\Services;

class NameService
{
    protected $di;
    public function __construct(\Pimple $di)
    {
        $this->di = $di;
    }

    public function getName()
    {
        return 'taka512';
    }
}

index.phpの修正

index.phpからNameServiceクラスを削除して、サービスの定義の部分のネームスペースを変更します。

$container['NameService'] = $container->share(function ($container) {
    return new \Taka512\Services\NameService($container);
});

これでネームスペースを利用してライブラリをもりもり作っていけるようになりました。

slimでpimpleを使う

pimpleはphpDIコンテナを実現するためのライブラリです。
今回はslimでpimpleを使ってみます。

インストール

composer.jsonにpimpleを追加

$ vi composer.json
"require": {
    "slim/slim": "2.*",
    "slim/extras": "2.0.*",
    "twig/twig": "1.*",
    "pimple/pimple": "1.0.0"
$ php composer.phar update

index.phpを編集

32~45行目でNameServiceを定義
19~23行目でNameServiceをpimpleに登録
26行目でNameServiceをpimpleから利用してます。

$ vi web/index.php
 10 $app = new Slim(array(
 ~略~
 19 $container = new Pimple();
 20 $container['app'] = $app;
 21 $container['NameService'] = $container->share(function ($container) {
 22     return new NameService($container);
 23 });
 25 $app->get('/', function() use ($container) {
 26     $name = $container['NameService']->getName();
 27     $container['app']->render('index.html.twig', array('name' => $name));
 28   });
 29
 30 $app->run();
 32
 33 class NameService
 34 {
 35     protected $di;
 36     public function __construct(Pimple $di)
 37     {
 38         $this->di = $di;
 39     }
 41     public function getName()
 42     {
 43         return 'taka512';
 44     }
 45 }


pimpleの何が嬉しいかというとLazyロードなのでNameServiceは26行目で実際に使われるタイミングで生成されます。

slimでログを出力

前回インストールしたslim/extrasを利用してログ出力を行う設定のメモ

ログディレクトリを作成

$ mkdir -p logs
$ chmod 777 logs

index.phpを編集

$app = new Slim(array(
            'view' => new Twig,
            'templates.path' => '../templates',
            'log.writer' => new \Slim\Extras\Log\DateTimeFileWriter(array(
                    'path' => '../logs',
                    'name_format' => 'Y-m-d',
                    'message_format' => '%label% - %date% - %message%'
                    ))
                ));

$app->get('/', function() use ($app) {
    $app->getLog()->debug('log'); // - level 4
    $app->getLog()->info('log');  // - level 3
    $app->getLog()->warn('log');  // - level 2
    $app->getLog()->error('log'); // - level 1
    $app->getLog()->fatal('log'); // - level 0

    $app->render('index.html.twig', array('name' => 'taka512'));
  });

index.phpにアクセスした後にログを見てみると出力されていることが確認できます。

$ tail -f logs/2013-06-29.log
DEBUG - 2013-06-29T16:56:47+09:00 - log
INFO - 2013-06-29T16:56:47+09:00 - log
WARN - 2013-06-29T16:56:47+09:00 - log
ERROR - 2013-06-29T16:56:47+09:00 - log
FATAL - 2013-06-29T16:56:47+09:00 - log

今回の作業をした後のディレクトリ構造はこんな感じとなります。

|-- composer.json
|-- composer.lock
|-- logs
|    |-- 2013-06-29.log
|-- templates
|    |-- index.html.twig
|-- vendor
|-- web
     |-- index.php

参考
https://github.com/codeguy/Slim-Extras#log-writers

slimでtwig連携

最近slimを使う機会がありそうなのでphpのマイクロフレームワークであるslimを基礎から触った。
まずはインストールしてslimとtwigで連携するところまで行う。

composerからのslimのインストール

$ curl -s http://getcomposer.org/installer | php
$ vi composer.json
{
    "require": {
        "slim/slim": "2.*",
        "slim/extras": "2.0.*",
        "twig/twig": "1.*"
    }
}
$ php composer.phar install

index.phpの作成

$ mkdir web
$ vi web/index.php
<?php
require '../vendor/autoload.php';

use Slim\Slim;
use Slim\Extras\Views\Twig as Twig;

$app = new Slim(array(
            'view' => new Twig,
            'templates.path' => '../templates'
            ));

$app->get('/', function() use ($app) {
    $app->render('index.html.twig', array('name' => 'taka512'));
  });
$app->run();

templateを作成

$ mkdir templates
$ vi templates/index.html.twig
hello {{ name }}

これでindex.phpにアクセスするとテンプレートの内容が表示されます。
そして今回のディレクトリ構造はこんな感じとなります。

|-- composer.json
|-- composer.lock
|-- templates
|    |-- index.html.twig
|-- vendor
|-- web
     |-- index.php

cookpad開発コンテスト24に参加してみた。

6/15(土)に第4回cookpad開発コンテスト24に参加して応募してみました。
結果は箸にも棒にもかからなかったのですが、提出までこぎ着けたのは有意義な経験だったので感想がてら振り返ってみました。

提出ソース

https://github.com/taka512/symfony_cookpad_dev4

提出サービス

http://cookpaddev4.taka512.net

1. 準備

前日までにプロビジョニング等の準備をしました。
構成は前回のブログで書いた構成でsymfony2 + mongod + mysql + memcached+(S
3+SES)構成でawsに環境を構築しました。
この時はまだ「位置情報」、「画像アップロード」ぐらい利用しようかなーぐらいなふわふわした考えでした。

2. 序盤(11:00〜)

9:00にお題の発表だったのですが、いきなりの寝坊ww
11:00ぐらいに目が覚めてお題を確認すると、「年をとった自分が使うサービス」という事で風呂に入りながら考え始める。
「老後 幸福」とかで検索したりでゼロから検討しました。結局、自分の老後で気になるのはお金かな!と思ったので細部はつめないで毎月の収入・支出を入力していくと定年後の月収を計算する家計簿的なサービスを構想しました。

3. 中盤(18:00~)

とりあえず認証機能とbootstrapを組み込んでみたら夜になっていて少し焦りだすw
この時点で当初の作りたいなーと考えていたフル機能はあきらめる。
とりあえず、1機能でも良いので実装して最低提出できる状態にする事を目指し始めました。

4. 終盤(3:00~)

眠くなってきて、どうせ駄目だし提出しなくても良いんじゃねとか悪魔の囁きが聞こえ始める。
後半は作業も雑になってきたので、この時間帯での機能追加は厳しい感じでした。
ただ、提出はしたいというモチベーションはあったので朝7:00ぐらいに作り上げて提出完了。
そのまま就寝

5. 結果

しょぼくても、やっぱり結果発表のページを開くのはドキドキしました。
結果についてはさらっと全提出サービス見てみましたがわりと納得な感じです。1位の作品は自分が時間をかけても作れる気がしませんでしたが2位以下はアイデア次第でなんとかなりそうな気もしたので自分の企画力の無さを痛感。

6. 感想(振り返り)

途中で外出したり集中力が途切れたりで、正味10時間ぐらいは頑張ったと思います。
反省点が多いですね。次回があったら反省を生かしていきたいですねw

・よかった点

  1. 前日有給取っていたので頭がすっきりした状態だった。
  2. サーバの構築は前もって準備しておいてよかった。

・反省点

  1. 日頃から企画力を鍛えてなかったので構想通り実現しても微妙なサービスとなった。
  2. 0から作る事が久しぶりだったので、まごついてスピード感を持って作成できなかった。
  3. 認証機能・bootstrap組込・ライブラリなど基礎的な機能は前もって作っておくべきだった。
  4. 結果的に認証機能は必要なかったので、前もって24時間で作れそうな機能を絞り込んでおくべきであった。