PHP
JavaScript
slim
Vue.js

PHPになるべく詳しくならずにWebアプリを作る (Slim + Vue.js)

More than 3 years have passed since last update.

Vueにゃん

PHPは簡単に動かせるのがいいところですね。

その良さを生かしつつ、薄いフレームワークの組み合わせで掲示板を作ってみたいと思います。


経緯


  • Node.js + Express使いだが、実際のところNode.jsをサーバで動かしていい案件はまれ

  • PHP案件はいっぱいだし、動くレンタルサーバも多いぞ

  • 動作環境としてのPHPは魅力なので触っておきたい

  • PHPにあまり詳しくないし、コードを書いている時間よりも調べ物に時間の方が長くなるのが辛い

  • PHPフレームワークも分厚いものが多く、調べ物に時間が取られてやはり辛い

  • 何でも屋になりたいわけではないので、PHPのことは詳しく知らない自分のままでいたい


作りたいもの

とりあえず一行掲示板。


考えた構成

スクリーンショット 2015-08-25 18.06.38.png


  • SPA(PHPを書く量を最低限にするため)

  • PHP5.5 + ビルトインサーバ

  • Slim Framework2 (3も気になるがとりあえず)

  • Vue.js

  • Sqlite(mysqlを使うのがかったるい)

また、Sqliteなら、さくらインターネットの最下位プランでも動作するだろうという目論見。


SlimでJSONサーバを書く

Slimはsinatraライクに書ける。

JSONを吐くだけなら下記のようにする。

$app->get("/items/", function() (){

echo '{"message" : "Hello, World"}';
}

とりあえず上記のように、適当なJSONを返すようにしておいて、先にフロントエンドを作るのが楽。


JSONを返す設定

JSONしか扱わないのであれば、ルーティング処理全体にContent-Typeを設定できる。下記のようにする。

$app = new \Slim\Slim();

$app->response->headers->set('Content-Type', 'application/json');


テーブルの作成

普通にPDOからSQLiteを使う。

1テーブル程度の小規模アプリなので、わざわざORMを使わなくても良さそう。

$db = new PDO('sqlite:bbs.db');

$db->exec('CREATE TABLE IF NOT EXISTS bbs(id INTEGER PRIMARY KEY, contents TEXT)');


記事一覧の取得

json_encodeを使って、DBからfetchしたものをそのままjsonに変換する。

$app->get("/items/", function() use ($app, $db){

echo json_encode($db->query('SELECT id, contents FROM bbs ORDER by ID DESC')->fetchAll(PDO::FETCH_ASSOC));
}


記事の投稿

$app->post("/items/", function() use ($app, $db){

$text = $app->request->post('text');
$db->prepare('INSERT INTO bbs(contents) VALUES(?)')->execute([$text]);
$result["status"] = "success";
$result["text"] = $text;
echo json_encode($result);
});


フロントエンドを作る

ビューのフレームワークとしてVue.js、Ajaxにはsuperagentを採用する。requireはbrowserifyで解決した。

フレームワークは別にVue.jsでなくても構わない。AngularでもReactでもjQueryでも素JSでも出来る事をやっている。

main.js

var Vue = require("vue");

var request = require("superagent");

new Vue({
el: "#main",
data: {
text: "",
items: []
},
methods: {
fetchPosts: function(){
var self = this;
request
.get("./api.php/items/")
.end(function(err, res){
self.items = res.body;
})
},
createPost: function(text){
var self = this;
request
.post("./api.php/items/")
.type('form')
.send({text: text})
.end(function(err, res){
if(err){
console.error(err);
}
self.text = "";
self.fetchPosts();
});
}
},
ready: function(){
this.fetchPosts();
}
})

index.html

<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="UTF-8">
<title>BBS</title>
<link rel="stylesheet" href="https://cdn.rawgit.com/mblode/marx/master/css/marx.min.css">
<link rel="stylesheet" href="./index.css">
</head>
<body>
<main id="main">
<h1>BBS</h1>
<textarea v-model="text" class="bbs__textarea"></textarea>
<button v-on="click: createPost(text)">投稿</button>
<div class="bbs__item" v-repeat="item: items">
<p>
{{item.contents}}
</p>
<p class="bbs__item__id">
No: {{item.id}}
</p>
<small></small>
</div>

</main>
<script src="dist/bundle.js"></script>
</body>
</html>

リクエスト先のURLが./api.php/〜などとなっている。たいていは.htaccessでapi.phpを削除するなどして、綺麗なURLに直すところ。

だが、SPAにしてしまえば、URLの遷移はJavaScript側に任せることができる。APIのURLが汚い分には、見ている人にはわからないので、このままでいいことにする。

Vue.jsでルーティングを行なう場合は、vue-routerdirectorを使うことになるが、今回はやらない。

余談だが、.htaccessに依存するということは、IISやnginxにデプロイしたり、ビルトインサーバで動作させることができなくなるので、いずれバッドノウハウになるのではと思う。


完成品

とりあえずPHPのビルトインサーバで動作させる。

php -S localhost:8000

スクリーンショット 2015-08-25 16.53.27.png

レポジトリはこちら:GitHub


終わりに

ちゃんとするなら、ユーザ管理とか削除編集、ページネーションなんかも入れないとですね。

あと、今回marxというCSSフレームワークを使ってますが、Bootstrapと比べて余計な色付けが少なく、とても使いやすいのでおすすめです。