友人と。
友人とフグを食べた。
正直あんまりフグとか食べた事なかったのよねぇ==;
オイシカッタ。
RedMineが使えるサーバー探し
プライベートな開発でもチケット管理ができる物が欲しいと嫁が言っていたので、仕事で使っているRedMineが入る鯖を探しました。
無論チケットを発行するのは嫁や友人で、実装するのが私。プライベートでも進捗管理されるという…なんて素敵。
要件は以下の通り。
2時間程調べた結果
さくらインターネット
http://www.sakura.ne.jp/
スタンダードコース月額
500円さくらVPS
http://vps.sakura.ad.jp/
さくらのVPS 512コース
980円IIJ
http://www.iij.ad.jp/GIO/
IIJ GIOホスティングパッケージサービス ベーシック
4,000円カゴヤ
http://www.kagoya.jp/cloud/vps/
カゴヤ・クラウド・VPS
980円heteml
http://heteml.jp/service/charge/
1,500円Heroku
http://devcenter.heroku.com/articles/s3
EC2借りないといけないから・・・
3,000円
なかなか見つかりません。
さくらVPSがやっぱり良いのかなーと考えていて・・・
最後に見つけたのが
ファーストサーバー
http://server-cowboy.jp/?bid=gtop
サーバーカウボーイ
416円
やっすー!どこかで聞いた数字だけども、これでいいんじゃないの?
インストールできる物の中を見てみるとたくさんある事ある事。
ブログ・CMS
コミュニティ
Eコマース
- EC-CUBE
- Magento
アンケート
- Lime Survey
掲示板
フォトギャラリー
- Zenphoto
Wiki
バグ管理
- Mantis
プロジェクト管理
テンプレート
RedMineみっけ。
phpBBみっけ。
他にもOpenPneがあるということはSymfonyも入るってこと。
これで416円は安すぎやしませんか?
で、早速作ってみました。
http://n416.server-cowboy.net/bts/
作成まで10分。
まずは無料で使いたおして見る事にします。
symfony 1.4オブジェクトルート
要件:オブジェクトルートを使って、部屋の一覧を表示するアプリケーションを作成する
プロジェクトのディレクトリを作成します。
以下のコマンドをxampshell上で流します。
cd c:\ mkdir object_routeing cd object_routeing
プロジェクトを作成します。
以下のコマンドをxampshell上で流します。
symfony generate:project objectrouteing
DBを作成します。
C:\object_routeing\config\databases.ymlを確認後、以下のコマンドをxampshell上で流します。
symfony doctine:build-db
phpMyAdmin等でDBが作成されていることを確認します。
frontendアプリケーションを作成します。
以下のコマンドをxampshell上で流します。
symfony generate::app frontend
Apacehの設定を修正します。
C:\xampp\apache\conf\httpd.confを任意のエディタで修正してください。
Listen 80 <VirtualHost *:80> DocumentRoot "C:\object_routeing/web" DirectoryIndex index.php ErrorLog logs/error_log_object_routeing CustomLog logs/access_log_object_routeing common <Directory "C:\object_routeing/web"> AllowOverride All Allow from All </Directory> Alias /sf "C:\xampp\php\PEAR\data\symfony\web\sf" Alias /m/sf "C:\xampp\php\PEAR\data\symfony\web\sf" <Directory "C:\xampp\php\PEAR\data\symfony\web\sf"> AllowOverride All Allow from All </Directory> </VirtualHost>
http://localhost/にアクセスして確認します。
スキーマを変更します
C:\object_routeing\config\doctrine\schema.yml
Room: actAs: Timestampable: columns: name: { type: string(255) } prefecture_code: { type: integer(2) } line_code: { type: string(4) } indexes: myindex: fields: [prefecture_code] relations: Prefecture: { class : Prefecture, local: prefecture_code, foreign: prefecture_code, type: one } Prefecture: actAs: Timestampable: columns: prefecture_code: { type: integer(2), primary: true } us_name: { type: string(32) } name: { type: string(4) }
SQLを作成します。
以下のコマンドをxampshell上で流します。
symfony doctrine:build --sql
SQLを確認します。
C:\object_routeing\data\sql\schema.sqlをエディタで開き確認してください。
CREATE TABLE prefecture (prefecture_code SMALLINT, us_name VARCHAR(32), name VARCHAR(4), created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY(prefecture_code)) ENGINE = INNODB; CREATE TABLE room (id BIGINT AUTO_INCREMENT, name VARCHAR(255), prefecture_code SMALLINT, line_code VARCHAR(4), created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, INDEX myindex_idx (prefecture_code), PRIMARY KEY(id)) ENGINE = INNODB; ALTER TABLE room ADD CONSTRAINT room_prefecture_code_prefecture_prefecture_code FOREIGN KEY (prefecture_code) REFERENCES prefecture(prefecture_code);
テーブルを作成します。
以下のコマンドをxampshell上で流します。
symfony doctrine:insert-sql
マスターデータを作成します。fixtures.ymlを編集します。
C:\object_routeing\data\fixturesを任意のエディタで、追記してください。
Prefecture: 東京: prefecture_code: 9 us_name: tokyo name: 東京 大阪: prefecture_code: 27 us_name: osaka name: 大阪 Room: bukken1: Prefecture: 東京 name: 東京の部屋1 bukken2: Prefecture: 東京 name: 東京の部屋2 bukken3: Prefecture: 大阪 name: 大阪の部屋1 bukken4: Prefecture: 大阪 name: 大阪の部屋2
fixtures.ymlの内容を、テーブルに入れます
以下のコマンドをxampshell上で流します。
symfony doctrine:data-load
phpMyAdmin等でDBの中にデータが挿入されていることを確認します。
http://localhost/phpmyadmin/
※もしも文字化けを引き起こしている場合は、fixtures.ymlあるいは、データーベースがutf-8ではない可能性があります。
fixtures.ymlがutf-8で無い場合はutf-8で保存し、データーベースがutf-8で無い場合は
ALTER TABLE `prefecture`
DEFAULT CHARACTER SET=utf8;
といったようなSQLを通すか、一度データーベースを削除し、
my.iniの[mysqld]の項目以下にdefault-character-set=utf8という記載を入れ、再度作り直してください。
モジュールを作成します。
以下のコマンドをxampshell上で流します。
symfony generate:module frontend search
モデルを作成します。使うことになるクエリを記載します。
C:\object_routeing\lib\model\doctrine\RoomTable.class.php
<?php class RoomTable extends Doctrine_Table { public static function getInstance() { return Doctrine_Core::getTable('Room'); } public static function querySearchRooms() { $result = self::getInstance()->createQuery('r') ->leftJoin('r.Prefecture p'); return $result; } }
indexのアクションを作成します。今回はindexを、一覧にします。
C:\object_routeing\apps\frontend\modules\search\actions\actions.class.php
<?php class searchActions extends sfActions { public function executeIndex(sfWebRequest $request) { $p = $request->getParameter('p', 1); $pager = new sfDoctrinePager('Room', 10); $pager->setQuery(RoomTable::querySearchRooms()); $pager->setPage($p); $pager->init(); $this->pager = $pager; } public function executeShow(sfWebRequest $request) { $this->room = $this->getRoute()->getObject(); } }
テンプレートを作成します。今回はページャーのインターフェイスを省いています。
C:\object_routeing\apps\frontend\modules\search\templates\indexSuccess.php
<?php if ($count = $pager->getNbResults()): ?> <?php echo $count ?> 件の物件がみつかりました。 <ul> <?php foreach ($pager->getResults() as $room): ?> <li><?php echo $room->getName() ?> <?php endforeach; ?> </ul> <?php else: ?> 物件はありません <?php endif; ?>
http://localhost/search/indexにアクセスして確認します。
続いて一件表示用にアクションとテンプレートを追加しましょう
searchにShowアクションを追加します。
C:\object_routeing\apps\frontend\modules\search\actions\actions.class.phpを開いて以下のメソッドを追加します。
public function executeShow(sfWebRequest $request) { $DQL = RoomTable::querySearchRooms(); $id = $request->getParameter("id"); $DQL->addWhere('id=?', $id); $this->room = $DQL->fetchOne(); }
テンプレートを作成します。
C:\object_routeing\apps\frontend\modules\search\templates\showSuccess.php
<h2><?php echo $room->getName() ?></h2> <ul> <li>物件名:<?php echo $room->getName() ?></li> <li>都道府県:<?php echo $room->getPrefecture()->getName() ?></li> </ul>
http://localhost/frontend_dev.php/search/show/id/1にアクセスして確認します。
下準備はここまでになります。
本当は一覧のところにある
ですが、この実装方法だと、渡すパラメーターが変わる度actionソースの変更を行うことになり、あまり望ましい状態とは言えません。
今回はオブジェクトルートという方法でもっと優雅に解決をしましょう。
テンプレート側は
<li><?php echo link_to($room->getName(), 'room_show', $room) ?>
と記載しておきましょう。
room_showというルーティングをオブジェクトルートで対応したいと思います。
homepage: url: / param: { module: default, action: index } room_show: url: /room/:prefecture_us_name/:id class: sfDoctrineRoute options: { model: Room, type: object, method: fetchOneByIdAndPrefectureUsName } param: { module: search, action: Show } requirements: id: \d+ sf_method: [get] default_index: url: /:module param: { action: index }
room_showルートは、URLにすると
/localhost/room/tokyo/1
といった雰囲気になります。
urlの中で書いたprefecture_us_nameやidは、下のクラスのアクセサとして機能します。idであればgetIdにmprefecture_us_nameはgetPrefectureUsNameに対応します。
getIdは存在するので値が入りますが、getPrefectureUsNameは、こちらで作る必要があります。こちらは後で作成しましょう。どこに作成するのかというのは次で説明します。
optionsのmodelにはroomと記載しましたが、これはclassでsfDoctrineRuteと指定しているので、Doctrineのモデルを利用するという事を表しています。
つまり、先のgetPrefectureUsNameは、 Room.class.phpに記載するという事です。
methodは、fetchOneByIdAndPrefectureUsNameと指定していますが、これはどのメソッドを実行してコレクションを取り出すのかを指しています。
よって、Roomのコレクションオブジェクトである、RoomTable.class.phpに書きます。
では実際に
Room.class.phpとRoomTable.class.phpにメソッドを実装しましょう。
C:\object_routeing\lib\model\doctrine\Room.class.phpを任意のエディタで開いて編集します。
class Room extends BaseRoom { public function getPrefectureUsName() { return $this->getPrefecture()->getUsName(); } }
C:\object_routeing\lib\model\doctrine\RoomTable.class.phpを任意のエディタで開いて以下のメソッドを追加します。
public function fetchOneByIdAndPrefectureUsName($params) { return self::getInstance()->createQuery('r') ->leftJoin('r.Prefecture p') ->where('r.id = ?', $params['id']) ->andWhere('p.us_name = ?', $params['prefecture_us_name']) ->fetchOne(); }
さらにアクション側もこのルーティングに任せる修正を加えます。executeShowメソッドを変更します。
C:\object_routeing\apps\frontend\modules\search\actions\actions.class.phpを開いて以下のメソッドを追加します。
public function executeShow(sfWebRequest $request) { $this->room = $this->getRoute()->getObject(); }
シンプルなコードになりました。
これで、room_showルートは完成しています。
実際にアクセスをしてみましょう。
http://localhost/frontend_dev.php/room/tokyo/1 http://localhost/frontend_dev.php/room/osaka/3
はアクセスできますが
http://localhost/frontend_dev.php/room/osaka/1