[cakePHP] floatのフィールドが指数表記になっちゃう

cakePHPでfloatのフィールドを使った場合、7桁を超える数値を入れたらフォームで指数表記されちゃうのが困る。

これが

こうなる

仕方ないのでviewで

$this->data["Article"]["point"] = sprintf('%.2f', $this->data["Article"]["point"]);

って書いたらいけるかと思ったらいけなかった。
よくよく考えたらviewをレンダリングする前にformが出来上がってんじゃなかったっけ?w
ってことに気付いて素直にcontrollerに書いたら期待通りに動いた。

function edit($id = null) {
if (!$id && empty($this->data)) {
$this->Session->setFlash(__('Invalid article', true));
$this->redirect(array('action' => 'index'));
}
if (!empty($this->data)) {
if ($this->Article->save($this->data)) {
$this->Session->setFlash(__('The article has been saved', true));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The article could not be saved. Please, try again.', true));
}
}
if (empty($this->data)) {
$this->data = $this->Article->read(null, $id);
$this->data["Article"]["point"] = sprintf('%.2f', $this->data["Article"]["point"]);
}
}


何かイマイチすっきりしないのですが、他の解決策ないのかねぇ?

Filed under: cakePHP,PHP,Programming — maesan 5:17 PM

[cakePHP] 1.3でForm->selectのパラメータ変わったのか

今までだと、formヘルパーを使って空白を出さないselectは以下の様に書いてました

echo $this->Form->select('hoge_id', $hoges, null, null, false);

で1.3でこれやるとダメで、ソース見たらこうやるのが正しいっぽい

echo $this->Form->select('hoge_id', $hoges, null, array('empty' => false));

だれかCookbookのフォームヘルパーのselectのページを修正してください><
http://book.cakephp.org/ja#!/ja/view/1430/select
↑英語版を見るとそっちは正しいみたいだった!

Filed under: cakePHP,PHP,Programming — maesan 11:31 PM

[cakePHP] PHP5.3にしたらDeprecatedが表示されまくったでござる

ちょっとMacBookのHDDの調子が悪くなってきたので一旦OSから再インストールして環境を再構築したのですが、PHP5.3にするとcakePHP1.2だとDeprecatedがでまくりでかなり鬱陶しい事になってしまいました。

php.iniを書き換えたり、cakePHPのソースを書き換えたりする方法は何となくイヤだったので、.htaccessで対応することにしました。

適当にcakePHPのルートの.htaccessに以下を追記すればおkでした

php_value error_reporting 22527

Filed under: cakePHP,PHP,Programming — maesan 12:26 PM

為替レートを取得するプログラム書いてみた

ちょっと自動で別通貨から日本円に変換する処理が必要になったのでなんとか自動で為替レートを取得できないかと試行錯誤してみた。

データソース

調べてみるとYahoo!ファイナンスやら証券会社のページをスクレイピングしてる人とか多いみたいですが、仕様が変わったりすると面倒だったり、何となく邪道な感じがしたので、為替レートをRSSで提供しているサイトを発見したのでそれをパースすることにしました。
使ったのはココ→http://xurrency.com/

方法

APIも用意されているみたいなのですが、アクセスキーを取得しないと1日10回までの制限があったり、商用利用じゃ無かったらお金はかからないっぽいのですが何となくAPIは使わずにRSSをパースすることにしました。
今回は日本円基準なのでhttp://xurrency.com/jpy/feedを使います。
最終的にはデータベースに格納することにしました。DBはこんな感じcakePHPとかで使えそうな構造にしました。

CREATE TABLE `currencies` (
`id` int(11) NOT NULL auto_increment,
`base` varchar(3) collate utf8_unicode_ci NOT NULL COMMENT '基準通貨',
`target` varchar(3) collate utf8_unicode_ci NOT NULL COMMENT '対象通貨',
`value` float NOT NULL COMMENT 'レート',
`inverse` float NOT NULL COMMENT 'レート逆数',
`created` datetime default NULL COMMENT '作成日時',
`modified` datetime default NULL COMMENT '更新日時',
PRIMARY KEY (`id`),
KEY `target` (`target`),
KEY `created` (`created`)
) ENGINE=InnoDB;

ソースコード

とりあえずサクっとPHPで作ってみた

<?php
// XML取得
$xml = file_get_contents('http://xurrency.com/jpy/feed');
// XML パーサー作ってパースする
$parser = xml_parser_create();
xml_parse_into_struct($parser, $xml, $values, $idx);
xml_parser_free($parser);

// とりあえずDB接続
$con = mysql_connect('localhost', 'root', 'root');
mysql_select_db('currency');
mysql_query('set names utf8');
// 挿入用のSQL
$sql_base = 'insert into currencies(base, target, value, inverse, created, modified)values("%s", "%s", %f, %f, "%s", now());';

$date = null;
foreach ($idx['DC:VALUE'] as $key => $val) {
if ($date == null) {
// RSSの構造によりdateが1個はじめにかぶるから1個ずらす
$date = date('Y-n-j H:i:s', strtotime($values[$idx['DC:DATE'][$key + 1]]['value']));
}
$data = array(
'value' => $values[$val]['value'],
'base' => $values[$idx['DC:BASECURRENCY'][$key]]['value'],
'target' => $values[$idx['DC:TARGETCURRENCY'][$key]]['value'],
'date' => $date,
);
$data['inverse'] = 1.0 / $data['value'];
$sql = sprintf($sql_base, $data['base'], $data['target'],
$data['value'], $data['inverse'],
$data['date']);
mysql_query($sql);
}
// おしまい
mysql_close($con);
?>

で見てもらうとわかると思うのですが、ちょっとXMLのパースの仕方が美しくない気がしません?何ていうか親子関係無視というかとりあえず上からパースしてタグ名でばらしてみましたみたいな?
なので最近お気に入りのPythonでも同じの書いてみた

#!/usr/bin/python
#coding -*- coding: utf-8 -*-

from xml.etree.ElementTree import ElementTree
from urllib import urlopen
import MySQLdb
import datetime

# ElementTreeを生成
xml = ElementTree(file=urlopen('http://xurrency.com/jpy/feed'))
# タグ名が"{ネームスペース}:タグ名"に展開されるのでネームスペースを書いとく
rss = 'http://purl.org/rss/1.0/'
dc = 'http://purl.org/dc/elements/1.1/'

# MySQL接続
con = MySQLdb.connect(db="currency", host="127.0.0.1", port=3306, user='root', passwd='root')
# 挿入用のSQL
base_sql = 'insert into currencies(base, target, value, inverse, created, modified)values("%(base)s", "%(target)s", %(value)f, %(inverse)f, "%(date)s", now());';

# itemタグ内に為替レートを持ってるので取得してループ回す
for items in xml.findall('.//{' + rss + '}item'):
currency = {}
for item in items.getiterator():
if item.tag == '{' + dc + '}value':
currency['value'] = float(item.text)
if item.tag == '{' + dc + '}baseCurrency':
currency['base'] = item.text
if item.tag == '{' + dc + '}targetCurrency':
currency['target'] = item.text
if item.tag == '{' + dc + '}date':
currency['date'] = datetime.datetime.strptime(item.text, "%a %b %d %H:%M:%S UTC %Y")
currency['inverse'] = 1.0 / currency['value']

sql = base_sql%{'base':currency['base'], 'target':currency['target'], 'value':currency['value'], 'inverse':currency['inverse'], 'date':currency['date']}
cur = con.cursor()
cur.execute(sql)

con.commit()

そこまでこだわるような物ではないのかもしれませんが、コッチの方が構造を解析している感じがして個人的には綺麗な気がします。

まとめ

頻繁にアクセスするのも申し訳ないので、1日に1回cronで取得してデータ溜めこむ予定。なんかに使えそうだしね。
何ていうか、とりあえず円高スゲー、早く外貨口座作ってそっちにお金移さないとダメだ。ま、そんなに日本円も持ってないけどなw

Filed under: cakePHP,PHP,Programming,Python — maesan 2:37 AM  Comments (1)

[cakePHP] Paginator->sortのデフォルトのソート方向を変更

cakePHPのPaginatorってスゴく便利でよく使ってるのですが、Paginator->sortで作るlinkのデフォルトのソート順を変更したかったのでソース追っかけてみた。
ソート順のデフォルトがascなのですが、ネタ的にdescでソートされてほしかったのです。

cakePHP 1.3.2ね
で目的のメソッドは cake/libs/view/helpers/paginator.php にありましたので
単純にデフォルトのdirectionがascなのをdescにしただけでおしまい


function sort($title, $key = null, $options = array()) {
$options = array_merge(array('url' => array(), 'model' => null), $options);
$url = $options['url'];
unset($options['url']);

if (empty($key)) {
$key = $title;
$title = __(Inflector::humanize(preg_replace('/_id$/', '', $title)), true);
}
//$dir = isset($options['direction']) ? $options['direction'] : 'asc';
//↑を↓にしただけ
$dir = isset($options['direction']) ? $options['direction'] : 'desc';
unset($options['direction']);

$sortKey = $this->sortKey($options['model']);
$defaultModel = $this->defaultModel();
$isSorted = (
$sortKey === $key ||
$sortKey === $defaultModel . '.' . $key ||
$key === $defaultModel . '.' . $sortKey
);

if ($isSorted) {
$dir = $this->sortDir($options['model']) === 'asc' ? 'desc' : 'asc';
$class = $dir === 'asc' ? 'desc' : 'asc';
if (!empty($options['class'])) {
$options['class'] .= ' ' . $class;
} else {
$options['class'] = $class;
}
}
if (is_array($title) && array_key_exists($dir, $title)) {
$title = $title[$dir];
}

$url = array_merge(array('sort' => $key, 'direction' => $dir), $url, array('order' => null));
return $this->link($title, $url, $options);
}

CakePHP 1.3によるWebアプリケーション開発―オープンソース徹底活用
掌田 津耶乃
秀和システム
売り上げランキング: 11952
Filed under: cakePHP,Programming — maesan 11:42 PM

[cakePHP] XML-RPCしてみた

ちょっとサーバー間で処理をさせたいことがあったのでXML-RPCしてみることにしました。
単純にGETとかPOSTとかでやってもよかったのですが、前からXML-RPCに興味があったのでちょっと勉強がてらやってみました。

前準備

で、簡単に調べたのですがズバリそのもの「How to create an XML-RPC server with CakePHP」ってのがあって、あまりにも簡単に出来すぎて勉強になりませんでしたw

とりあえずこのページからxmlrpc.zipてのをダウンロードしてapp/vendor/xmlrpc.phpにコピー

Controller

ま、これも上のページにサンプルがあるのでまんまコピーでおk
XML-RPCサーバークラスのインスタンスを作るときにコンストラクタにコールバックを渡せばおkなので例えばフィボナッチ数を返す処理をつくろうと思ったらこんな感じで


<?php

// Import the app/vendor/xmlrpc.php library
App::import('Vendor', 'xmlrpc');

class XmlRpcController extends AppController {

// This demo doesn't need models
var $uses = array();

// The XML-RPC server object
var $server = null;

function index() {

// Disable debug information
// Required to generate valid XML output
Configure::write('debug', 0);

// Avoids render() call
$this->autoRender = false;

// XML-RPC callbacks settings
// Use this parameter to map XML-RPC methods to your protected or private controller methods
$callbacks = array();
$callbacks['Fibonacci'] = array(&$this, '_fibonacci');

// Handle XML-RPC request
$this->server = new IXR_Server($callbacks);
}

// Protected Method
function _fibonacci($n) {
if ($n <= 2) {
return 1;
} else {
return $this->_fibonacci($n - 1) + $this->_fibonacci($n - 2);
}
}
}

?>

Client

次はそれを呼び出すクライアントを作ります。
クライアントはcakePHP関係なしな感じです。
コレもサンプルコピペでおkですが、まぁこんな感じで

client.php


<?php
require_once(dirname(__FILE__) . '/xmlrpc.php');

$url = 'http://localhost/xml_rpc';

$client = new IXR_Client($url);

if (!$client->query('Fibonacci', 30)) {
die('Something went wrong - '.$client->getErrorCode().' : '.$client->getErrorMessage());
}
echo $client->getResponse();
echo "\n";

?>

実行してみる

>php client.php
832040

まとめ

てな感じであまりにも簡単すぎるので全くXML-RPCの勉強にはなりませんでしたw
このままだとあんまり意味が無いので今度は別の言語でクライアント実装してみるかなと。。。
そういや昔SOAPとか流行ったからちょっと仕事で使ったけどXML-RPCってそれと同じようなもんだっけ?

Programming Web Services With Xml-Rpc
Simon St. Laurent Joe Johnston Edd Dumbill
Oreilly & Associates Inc
売り上げランキング: 159906
Filed under: cakePHP,Programming — maesan 1:47 AM

[cakePHP]Cookieの有効期限

cakePHPでユーザーの言語設定をCookieで設定しようと思ってね、Cookieコンポーネント使ってみてハマった
有効期限を90日とかにしようと思ってこうやったのね


$this->Cookie->write('user_lang', $lang, false, time() + 90 * 24 * 60 * 60);

そしたらブラウザとじたら何か消えるの、Cookie残らないわけですね。
何でかと調べたら、第4引数はタイムスタンプじゃなくて有効時間を設定するのが正しいっぽく


$this->Cookie->write('user_lang', $lang, false, 90 * 24 * 60 * 60);

が正しいらしい
PHPのsetcookieとは若干異なるのですね。。。
ちなみにtime() + 90 * 24 * 60 * 60ってやったら本来有効期限がすごくすごく未来の時間になるわけですが、有効期限が0になっちゃうのは2038年問題で32bitのintがオーバーフローするからだと思われます。

高速開発で差をつけろ!CakePHPの基礎とECサイト制作入門
小倉 実
オモドック
売り上げランキング: 163769
Filed under: cakePHP — maesan 3:44 PM

[cakePHP1.3]Htmlヘルパーのlinkとか多言語対応とか

cakePHPの1.3でのHtmlヘルパーなんだけど、
画像でリンクを貼ろうと思ったら


echo $this->Html->link($this->Html->image('hoge.png'), '/', null. null, false);

ってやってたはずなんだけど、1.3では動かなくってさ


echo $this->Html->link($this->Html->image('hoge.png'), '/', array('escape' => false));

ってやることになったらしい。
ついでに多言語対応なんだけど、今まで言語指定って”jp”でも”jpn”でも行けたはずなのですが、”jpn”でないとダメになったっぽい。


$this->Session->write('Config.language', 'jpn');
$this->Session->write('Config.language', 'eng');

みたいな
んではまた
CakePHP 1.3によるWebアプリケーション開発―オープンソース徹底活用

Filed under: cakePHP — maesan 11:18 PM

cakePHP1.3 $javascript->linkがない

jsファイル読み込むときに今まで
echo $javascript->link(‘hoge’);
ってやってきたんだけど、cakePHP1.3から
echo $Html->script(‘hoge’);
になったっぽい。
ajaxもなんか変わったっぽいからまた気づいたらメモる
CakePHP 1.3によるWebアプリケーション開発―オープンソース徹底活用

Filed under: cakePHP — maesan 12:07 AM

$this->renderElementが無くなった

cakePHP 1.3でViewのrenderElementがなくなったっぽい
使おうと思って定義されてないとかエラーでて気づいた
$this->renderElement(‘hoge’);
じゃなくて
$this->element(‘hoge’);
って使うようになったらしい。
あと、Model::delが無くなった(非推奨?)ので
Model::deleteを使うべきらしい。
→もともとSessionとかのメソッド名はdeleteだったのでなんか気持ち悪かったけど統一されてよかった
またなんかあったら書く
CakePHP 1.3によるWebアプリケーション開発―オープンソース徹底活用

Filed under: cakePHP — maesan 12:50 PM
 iTunes Store(Japan)
 iTunes Store(Japan)
 iTunes Store(Japan)
 iTunes Store(Japan)
 iTunes Store(Japan)