オレオレ MVC を作ってみる(1) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/1861
前回のコードを少し変更して wordpress のカテゴリ一覧とカテゴリ内の記事を表示させます。
■最初の index.php
まずは、クラス名とメソッドを取り出す index.php から。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
<?php
$url = $_GET['url'];
$url = strtolower($url);
$vars = preg_split('|/|',$url);
$params = array();
if ( count($vars) == 1 ) {
$base = $url;
$method = "index";
} else if ( count($vars) == 2 ) {
$base = $vars[0];
$method = $vars[1];
} else {
$base = $vars[0];
$method = $vars[1];
for($i=2; $i<count($vars); $i++ ) {
$params[] = $vars[$i];
}
}
$classfile = $base."_controller.php";
$classname = strtoupper(substr($base,0,1)).substr($base,1).'Controller';
echo "classfile: $classfile<br/>";
echo "classname: $classname<br/>";
echo "method: $method<br/>";
echo "param: ";print_r($params); echo "<br/>";
include('controllers/'.$classfile);
$c = new ReflectionClass($classname);
$obj = $c->newInstance();
$method = $c->getMethod($method);
$method->invokeArgs($obj,$params);
?>
</body>
GET で送られる URL から「/」でパースするところは同じで、メソッドのパラメータを受けれるようにします。これの難点は常に body タグ内に view のコードが入ってしまうことですよね。一旦他のレンダリングに任せて、その中で view のコードを呼ぶようにしないと、head タグなどが書き出せません。
■ビューを作る
<!-- views/categories/item.php --> <h1>カテゴリ一内の記事</h1> <table> <tr> <th>Post.id</th> <th>Post.post_title</th> <th>User.display_name</th> <th>Post.post_date</th> <th>Post.guid</th> </tr> <?php foreach($Categories as $item) : ?> <tr> <td><?php echo $item['Post']['id']; ?></td> <td><?php echo $item['Post']['post_title']; ?></td> <td><?php echo $item['User']['display_name']; ?></td> <td><?php echo $item['Post']['post_date']; ?></td> <td><?php echo $item['Post']['guid']; ?></td> </tr> <?php endforeach; ?> </table>
ビューの作りは CakePHP の *.ctp と同じ。このあたりは互換が保てて楽ちん。
■コントローラーを作る
<?php
include 'models/category.php';
class CategoriesController {
var $name = 'CategoriesController';
function index() {
// view に渡す変数
global $Categories;
// モデルを作成して
$category = new Category();
// 検索
$Categories = $category->find('all');
include('views/categories/index.php');
}
function item($slug) {
// view に渡す変数
global $Categories;
// モデルを作成して
$category = new Category();
// 検索
$Categories = $category->findBySlug($slug,10);
include('views/categories/item.php');
}
}
?>
コントローラーは、モデルを new してからメソッドを呼ぶだけ。最後に view をインクルードして表示ってな具合です。この include 部分を変えて index.php との連携を取らないといけませんね。
■モデルの基底クラスを作る
モデルの基底クラスを作りました。
<?php
class Model {
var $cn ;
function open() {
// $this->cn = new PDO("mysql:host=127.0.0.1;dbname=moonmile_cake",
// "moonmile_cake","cakephp");
$this->cn = new PDO("mysql:host=127.0.0.1;dbname=wordpress",
"wordpress","wordpress");
}
function close() {
$this->cn = null;
}
function query($sql) {
$this->open();
$results = $this->cn->query($sql);
$this->close();
return $this->toArray($results);
}
function toArray($stmt) {
$items = array();
foreach($stmt as $item) {
foreach($item as $key => $value) {
if (strpos($key,'.') == true ) {
list($table,$column) = split('\.',$key);
$tables[$table][$column] = $value;
}
}
$items[] = $tables;
}
return $items ;
}
}
?>
ひとまず、データベースの open と close は、ここから継承することにすると。後、クエリを実行した後で配列に直すのが前回はださかったので、toArray メソッドを作って自動化します。こうすることで、Term.term_id のような名前をクエリで付けておけば $item[‘Term’][‘term_id’]のように参照ができます。
■モデルを作る
この基底クラスを継承して Category モデルクラスを作ります。
<?php
require('lib/model.php');
class Category extends Model {
var $name = 'Category';
function find($type) {
$sql = <<< HERE
select
Term.term_id `Category.term_id`,
Term.name `Category.name`,
Term.slug `Category.slug`
from
wp_terms as Term
inner join wp_term_taxonomy as TermTaxonomy
on ( Term.term_id = TermTaxonomy.term_id )
WHERE
TermTaxonomy.taxonomy = 'category'
order by Term.term_id
;
HERE;
$items = $this->query($sql);
return $items ;
}
function findBySlug($slug,$max) {
$sql = <<< HERE
select
Post.ID `Post.id`,
Post.post_title `Post.post_title`,
User.display_name `User.display_name`,
Post.post_date `Post.post_date`,
Post.guid `Post.guid`
from
wp_terms as Term
inner join wp_term_taxonomy as TermTaxonomy
on ( Term.term_id = TermTaxonomy.term_id )
inner join wp_term_relationships as TermRelationship
on ( TermTaxonomy.term_taxonomy_id = TermRelationship.term_taxonomy_id )
inner join wp_posts as Post
on ( TermRelationship.object_id = Post.ID )
inner join wp_users as User
on ( Post.post_author = User.ID )
WHERE
TermTaxonomy.taxonomy = 'category'
AND Post.post_status = 'publish'
AND Term.slug = '$slug'
order by Post.post_date desc
limit $max ;
HERE;
$items = $this->query($sql);
return $items ;
}
}
?>
完全にクエリを書くということで、非自動化 O/R マッピングッ!!! SQL を分かっている場合はこれでも十分かなぁと。下手に Model::$belongsTo 等で悩むよりは、と考えてしまいます。
余談ですが、CakePHP のアソシエーションは、LINQ to Entities のアソシエーションのようにグラフィカルかつダイアログ等で入力してから、コードに直してやれば良いかと思っています。LINQ to Entities の設定って XML ファイルに書き出されるので、同様に CakePHP のアソシエーションを XML に設定しておいて読み込ませるってこともできますね。
このオレオレ MVC の O/R マッピングは完全に SQL 文を書くしかない体制なので、この部分をコピー&ペーストして MySQL Workbench で実行してチェックってことになります。なので、inner join を使ってきっちり結合させます。
■実行してみる
これだけのコードで MVC が実現できます(非常にチープですが)。
まぁ、これだとリストの表示しかできないので、お次は insert, update, delete ですね。いや、その前にレイアウト読み込みをさせないと。


