Symfony2、lithiumとZendのコンポーネントを使った簡単なフレームワーク
最近Symfony2の勉強をしてまして、
Symfony2のコンポーネントがスタンドアローンということで、簡単なサイトでも使えそうです。
調べてみたら、他のPHPのフレームワークでもスタンドアローンのコンポーネントが多いのようです。
今回は、Symfony2のClassLoaderとHttpFoundation、lithiumのRouter、ZendのLogコンポーネントを使って、
簡単なフレームワークを作ってみました。
●機能
・DB連動(sqlite使用)
・ルーティングが設定できる
・ログ出力
●フォルダ構造
.htaccess
index.php
bootstrap.php
routing.php
controllers.php
vendors
lithium
Pimple※
Symfony
zf2
data
setupDb.php
※
sensiolabs社(symfonyを作った会社)製簡単なDIC(Dependency Injection Container)
http://pimple.sensiolabs.org/
http://itpro.nikkeibp.co.jp/article/COLUMN/20060628/241982/
●DB初期化
data/setupDb.phpを使ってDB初期化をする
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?php try { $dbPath = __DIR__.'/database.sqlite'; $dbh = new PDO('sqlite:'.$dbPath); } catch(PDOException $e) { die('Panic! '.$e->getMessage()); } $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbh->beginTransaction(); $query = <<<EOF DROP TABLE IF EXISTS test_contents; CREATE TABLE test_contents ( id INTEGER PRIMARY KEY, content TEXT, created_at TIMESTAMP ); INSERT INTO test_contents VALUES(1,'テストコンテンツその1','2012-03-07'); INSERT INTO test_contents VALUES(2,'テストコンテンツその2','2012-03-07'); INSERT INTO test_contents VALUES(3,'テストコンテンツその3','2012-03-07'); EOF; $dbh->exec($query); $dbh->commit(); |
●apache設定
front controllerを使うには、apacheのrewrite engineをONにすることが必要
.htaccess
1 2 3 4 5 6 7 8 9 | <IfModule mod_rewrite.c> RewriteEngine On # don't rewrite things that point to real files RewriteCond %{REQUEST_FILENAME} !-f # but rewrite everything else to index.php RewriteRule ^(.*)$ index.php/$1 [QSA,L] </IfModule> |
●front controller→小さいPHPファイル
index.php
1 2 3 4 5 6 7 | <?php $c = require 'bootstrap.php'; require 'routing.php'; require 'controllers.php'; $response = _run_application($c); $response->send(); |
●bootstrap
bootstrap.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | <?php // 大体のPHPフレームワークのautoloaderの機能が簡単で同じ。今回はsymfony2のautoloaderを使用 require __DIR__.'/vendors/Symfony/Component/ClassLoader/UniversalClassLoader.php'; use Symfony\Component\ClassLoader\UniversalClassLoader; // autoloader設定 $loader = new \Symfony\Component\ClassLoader\UniversalClassLoader(); $loader->registerNamespace('Symfony', __DIR__.'/vendors'); $loader->registerNamespace('lithium', __DIR__.'/vendors'); $loader->registerNamespace('Zend', __DIR__.'/vendors/zf2/library'); $loader->register(); // DICをロード require __DIR__.'/vendors/Pimple/lib/Pimple.php'; // namespace use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use lithium\net\http\Router; use lithium\action\Request as Li3Request; use Zend\Log\Logger; use Zend\Log\Writer\Stream; function _run_application(Pimple $c) { // routingを解析 $c['router']->parse($c['li3_request']); // 解析結果をパラメーターとしてsymfonyのrequestに追加 $c['request']->attributes->add($c['li3_request']->params); // symfonyのrequestにcontrollerのパラメーターを取得 // 取得できない場合は、'error404'を与える $controller = $c['request']->attributes->get('controller', 'error404'); if ($controller == 'error404') { $msg = sprintf('Controller not found for "%s"', $c['request']->getPathInfo()); // エラーログ出力 $c['logger']->log($msg, Logger::ERR); } else { // INFOログ出力 $c['logger']->log(sprintf('Found controller "%s"', $controller), Logger::INFO); } // controller(symfonyのaction相当)実行 $response = call_user_func_array($controller, array($c['request'], $c)); if (!$response instanceof Response) { throw new Exception(sprintf('Your controller "%s" did not return a response!!', $controller)); } return $response; } /** * *************** DIC設定 */ $c = new Pimple(); // 設定 $c['connection_string'] = 'sqlite:'.__DIR__.'/data/database.sqlite'; $c['log_path'] = __DIR__.'/data/web.log'; // サービス設定 // DB $c['connection'] = $c->share(function(Pimple $c) { return new PDO($c['connection_string']); }); // Request $c['request'] = $c->share(function() { return Request::createFromGlobals(); }); // Router $c['li3_request'] = $c->share(function(Pimple $c) { $li3Request = new Li3Request(); $li3Request->url = $c['request']->getPathInfo(); return $li3Request; }); $c['router'] = $c->share(function() { $router = new Router(); return $router; }); // logger $c['logger_writer'] = $c->share(function(Pimple $pimple) { return new Stream($pimple['log_path']); }); $c['logger'] = $c->share(function(Pimple $pimple) { return new Logger($pimple['logger_writer']); }); return $c; |
●routing設定
routing.php
1 2 3 4 5 | <?php $c['router']->connect('/contents', array('controller' => 'contents')); // routingの追加はここから $c['router']->connect('/', array('controller' => 'homepage')); |
●controller設定
controllers.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; function homepage(Request $request) { return new Response('<h1>テストコンテンツのトップページへよこそう!</h1>'); } function contents(Request $request, Pimple $c) { $dbh = $c['connection']; $sql = 'SELECT * FROM test_contents'; $content = '<h1>テストコンテンツのリスト</h1>'; $content .= '<ul>'; foreach ($dbh->query($sql) as $row) { $content .= sprintf('<li>%s - 時間 %s</li>', $row['content'], $row['created_at']); } $content .= '</ul>'; return new Response($content); } function error404(Request $request) { $response = new Response('<h1>ページが見つかりませんでした!</h1>'); $response->setStatusCode(404); return $response; } |
●サービスの拡張について
これから、新しいページを作りたい場合は、
面倒なURL判断が一切心配なく、
routing.phpにroutingの設定を行ってから、controllers.phpにcontroller関数を追加
(
たとえば、contents_detailを追加したい場合は、
まずrouting.phpに
$c[‘router’]->connect(‘/content_detail/{:id}’, array(‘controller’ => ‘content_detail’, ‘id’ => null));を追加してから、
controllers.phpに
content_detailという関数を追加
)
すればいいです
(もちろん、templateが必要な場合は適当viewer追加)。
Author Profile
スターフィールド編集部
SHARE