symfony1.2使用1.0插件sfFeedPlugin一例

最近经常和symfony插件打交道, 发现插件真是提高开发效率和重用性的一个非常棒的解决方案, 真是居家旅行之必备良药.

废话到此为止, 今天研究了一下fabien potencier写的sfFeedPlugin, 官方出的插件品质没的说, 只是有一个问题比较头痛, 就是插件很久没有更新了在symfony1.2下无法使用命令进行安装. 这个问题比较普遍, 因为symfony1.0, 1.1, 1.2的差异还是比较大的,  插件package的结构也稍有不同, 但由于symfony基本结构和方法并没有发生太多变化, 所以很多插件其实都可以在其他版本上正常运行,  插件作者都没有精力也没有兴趣对这些问题进行修改, 这都在情理之中.  这样本文第一个要解决的问题就出现了,  如何安装不同版本的插件.

在1.2上安装sfFeedPlugin

其实我们要作的很简单, 只需要在旧版本上进行安装然后将插件目录copy到1.2的项目下就可以了.

首先检出或者安装旧版本的symfony源代码
$ svn co http://svn.symfony-project.com/branches/1.0 symfony1.0然后创建一个旧版本的项目
$ mkdir test$ cd test$ ../symfony1.0/data/bin/symfony init-proj test下一步,安装插件
$ ./symfony plugin-install http://plugins.symfony-project.org/sfFeedPlugin最后一步, 将插件目录复制到1.2项目中的plugins目录下.
$ cp -rf plugins/sfFeedPlugin pathto1.2project/plugins有些插件下还有web目录, 这样你还需要将web下以该插件名命名的文件夹复制到1.2项目的web目录下以确保插件完整.

这样其实就已经安装好了, 查看sfFeedPlugin的源代码会发现其实是一个类库, 参考网上其他的文章简单写了一个例子.

使用过程中发现了一个可能是兼容性问题, sfFeed.class.php中的context对象不正确, 将所有使用context的地方换成sfContext::getInstance()就可以了.

apps/frontend/modules/feed/actions/actions.class.php
public function executeIndex(sfWebRequest $request)
{
// get shops
$c = new Criteria();
$shops = ShopPeer::doSelect($c);
$feed = new sfRss201rev2Feed();
// channel
$feed->setTitle('New Shops');
$feed->setLink('@homepage');
$feed->setFeedUrl('feed/index');
$feed->setDescription('All the new shops.');
$feed->setAuthorEmail('***@gmail.com');
$feed->setAuthorName('maker');
// items
foreach($shops as $shop)
{
$item = new sfFeedItem();
$item->setTitle($shop->getName());
$item->setLink('shop/index');
$item->setAuthorName('maker');
$item->setAuthorEmail('***@gmail.com');
$item->setPubdate($shop->getCreatedAt('U'));
$item->setUniqueId($shop->getName());
$item->setDescription($shop->getDescription());
$feed->addItem($item);
}
$this->feed = $feed;
}
apps/frontend/modules/feed/config/view.yml
all:
has_layout: off
template:   feed
http_metas:
content-type: text/xml

apps/frontend/modules/feed/templates/indexSuccess.php
<?php decorate_with(false); ?>
<?php echo $feed->getFeed(); ?>
访问http://project/feed/index, 源代码如下
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>New Shops</title>
<link>http://project/feed/index</link>
<description>All the new shops.</description>
<language>en</language>
<item>
<title>shop name</title>
<description>shop description</description>
<link>http://first-symfony-project/pc_dev.php/</link>
<guid isPermalink="false">shop name</guid>
<author>***@gmail.com (maker)</author>
<pubDate>Thu, 15 Jan 2009 16:12:11 +0800</pubDate>
</item>
<item>
<title>shop name</title>
<description>shop description</description>
<link>http://first-symfony-project/pc_dev.php/</link>
<guid isPermalink="false">shop name</guid>
<author>***@gmail.com (maker)</author>
<pubDate>Thu, 15 Jan 2009 16:12:11 +0800</pubDate>
</item>
</channel>
</rss>

archlinux 安装 LAMP环境

archlinux 安装 LAMP环境

archlinux 据说是很牛的系统  试了以后 的确很牛,牛到我累了好长时间也不能成功驾驭

不过工作重要 还是先说说LAMP环境如何来做吧。

archlinux 有一个传说中很牛的 类似 apt-get 的东西  叫 pacman

用命令

pacman -S apache mysql php

就可以直接把 apache mysql php 基本安装完成 我不确定顺序是否有影响 但是我建议大家如果想事少一点还是按这个顺序来吧

不知道从什么时候开始 php有一个openbase_dir 的变量 这个变量标识哪些目录可以用来存放 php文件 即 document root 一定要在openbase_dir 里,否则不会执行

而且 archlinux 的默认的document  root 是 /srv/html 这个目录默认没有 而且当安装apache的安装后 我习惯的测了一下 ,这个目录不存在,会让apache 启动失败,所以我改成了/var/www 结果 php 放在/var/www下时 ,由于不在 openbase_dir里 所以不能执行 而且不报任何错误(由于php.ini的设置)所以就会出现 要么不解释 php文件 ,解释的时候 什么也没有 就是一片空白 一点错误也不报。 最难受的是  当GOOGLE  archlinux lamp 的时候 一点也没有文章 提及这一现像,也没有解决方案 ,让我弄了好长时间才发现解决办法 。

解决办法就是 在php.ini 里 修改openbase_dir  或是 对应的不要修改 把文件直接放到/srv/html里

mysql 也是用得相当吃力 命令行下可以很好的进入 但是phpmyadmin就不可以 提示 连接被拒 也想过很多办法  但是未果 。后来发现不知道什么时候,或是哪条设置让 phpmyadmin不能用root   没有密码的情况下 连接 到mysql 没有办法  只好强行新建一个用户 给出所有权限。还有一点 现在MYSQL聪明了,在 skip-grant-tables时不可以对用户进行操作,这样是安全了很多,也让忘了密码的时候没有办法 进行找回

OK 只要注意以上两点基本上LAMP环境没有问题了

发布你的symfony插件

symfony插件编写一例:QRcodePlugin》一文中我们编写了一个用来生成QRcode 的symfony插件, 本文我们将会将QRcodePlugin发布到symfony官方的插件库(http://www.symfony-project.org/plugins/).

发布插件的程序比较繁琐, 方便起见我们使用一款插件来辅助我们发布插件 sfTaskExtraPlugin, 该插件扩展了symfony命令, 使用generate:plugin可以生成插件的基本目录结构, plugin:package命令来帮助我们将插件打包.

接下来是最复杂的地方, symfony是通过PEAR来进行packages管理的, 所以我们要将插件打成一个PEAR package. 一个发布到官方插件库的插件需要有一个LICENSE和一个README, 这两个文件要放在插件根目录下. README里需要写插件的说明和使用方法, README 使用 Markdown format, LICENSE文件是许可协议, symfony支持MIT, BSD, LGPL, 和PHP协议.

一个package包括package.xml和源代码, package.xml里对插件进行了详细的描述, 包括目录结构, 插件版本, 更新记录等等. 关于该文件的详细说明请参考PEAR package syntax(http://pear.php.net/manual/en/guide-developers.php)

由于package.xml结构复杂, 所以不做过多的讲解, 我们使用前面介绍过的plugin:package命令来生成package.xml.
$./symfony plugin:package QRcodePlugin> Summarize your plugin in one line:用一行文字对插件进行简单的描述
$create QR code image> Lead developer name:主要开发者的名字
$maker> Lead developer email主要开发者的邮箱
$****@gmail.com> Lead developer username:主要开发者的symfony帐号, 没有去这里注册 http://www.symfony-project.org/user/new
$m4ker> Plugin version number (i.e. "1.0.5"):package版本号
$0.0.1> Plugin stability:发布状态, 这里注意1.0.0一下能使用alpha和beta, 1.0.0以上可以使用stable, 再具体就没有研究了.
$beta运行完毕会生成一个QRcodePlugin-0.0.1.tgz, 但是这个文件是不能直接上传到插件库中的, 因为package.xml中没有changelog.我们把包打开, 编辑package.xml
$tar zxf QRcodePlugin-0.0.1.tgz$vi package.xml找到

<changelog />

替换成

<changelog>
<release>
<version>
<release>0.0.1</release>
<api>0.0.1</api>
</version>
<stability>
<release>beta</release>
<api>beta</api>
</stability>
<license uri="http://www.symfony-project.com/license">
MIT license
</license>
<date>2009-1-16</date>
<license>MIT</license>
<notes>
* maker: First release of the plugin
</notes>
</release>
</changelog>

然后再原样打包
$tar zcf QRcodePlugin-0.0.1.tgz QRcodePlugin-0.0.1/ package.xml这样我们就生成了一个可以上传到官方插件库的package了, 接下来呢, 我们要去symfony 官方网站创建一个Plugin, 如果你没有帐号, 要先创建一个帐号.

http://www.symfony-project.org/user/new

screenshot-11

然后登录到 plugin system(http://www.symfony-project.org/plugins/)中.

screenshot-2Create a new plugin 进入插件创建页面(http://www.symfony-project.org/plugins/new)

screenshot-5在创建页面我们需要填写

插件名: QRcodePlugin

是否加入插件库: 选中

插件源地址: http://svn.symfony-project.com/plugins/QRcodePlugin

插件主页: http://www.foolbirds.com

Ticketing URL:

选择支持哪种ORM?

描述: …

图片:

分类:

填写完毕之后提交, 我们就创建了一个Plugin.然后我们来上传QRcodePlugin的第一个版本, 进入插件首页(http://www.symfony-project.org/plugins/QRcodePlugin)中的Admin页面.

screenshot-6

在New Release表单中上传我们的QRcodePlugin-0.0.1.tgz

screenshot-7

上传成功后我们会看到Releases中多了一项类似下面这样:

screenshot-8

这样我们的插件就成功的加入到了官方插件库, 接下来我们使用官方方法测试一下是否可以安装.
$./symfony plugin:install QRcodePlugin --release=0.0.1>> plugin    installing plugin "QRcodePlugin"
>> sfPearFrontendPlugin Attempting to discover channel "pear.symfony-project.com"...
>> sfPearFrontendPlugin downloading channel.xml ...
>> sfPearFrontendPlugin Starting to download channel.xml (663 bytes)
>> sfPearFrontendPlugin .
>> sfPearFrontendPlugin ...done: 663 bytes
>> sfPearFrontendPlugin Auto-discovered channel "pear.symfony-project.com", alias
>> sfPearFrontendPlugin "symfony", adding to registry
>> sfPearFrontendPlugin Attempting to discover channel
>> sfPearFrontendPlugin "plugins.symfony-project.org"...
>> sfPearFrontendPlugin downloading channel.xml ...
>> sfPearFrontendPlugin Starting to download channel.xml (639 bytes)
>> sfPearFrontendPlugin ...done: 639 bytes
>> sfPearFrontendPlugin Auto-discovered channel "plugins.symfony-project.org", alias
>> sfPearFrontendPlugin "symfony-plugins", adding to registry
>> sfPearFrontendPlugin downloading QRcodePlugin-0.0.3.tgz ...
>> sfPearFrontendPlugin Starting to download QRcodePlugin-0.0.3.tgz (1,035,616 bytes)
>> sfPearFrontendPlugin ...done: 1,035,616 bytes
>> sfSymfonyPluginManager Installation successful for plugin "QRcodePlugin"
>> sfSymfonyPluginManager Installing web data for plugin
$ls plugins>>QRcodePlugin
安装成功, 本文完.

symfony插件编写一例:QRcodePlugin

创建symfony插件》一文中对如何编写插件进行了简单的介绍, 下面用一个例子来详细讲解一些如何创建一个生成QRcode的插件.

什么是QR code(QR码)?

简单来说, QR code是用来存储数据的矩形黑白点阵, 可以在很小的图片中存储大量的数据, 在移动领域应用广泛. 详细的说明请参考维基百科(http://zh.wikipedia.org/wiki/QR%E7%A2%BC)

应项目需求, 我们要编写一个用来生成QR code的Helper, 为了更好的重用性, 我们要将这个Helper写成一个插件.

首先, 创建目录结构
$cd plugins$mkdir QRcodePlugin$cd QRcodePlugin$mkdir lib web$mkdir lib/helper

生成QR code的过程中我们使用到了一个第三方类库 qr_img0.50g, 在readme中我们找到了使用方法如下:

php/qr_img.php?d=data[&e=(L,M,Q,H)][&s=int size][&v=(1-40)][&t=J]
[&m=(1-16)&n=(2-16)[&o=original data][&p=(0-255)]]

访问该文件会根据url中的参数生成一个QR code 图片, 我们只要将这个库放到web目录下就可以了.

$mv qr_img0.50g pathtoproject/plugins/QRcodePlugin/web/qr_img

然后我们来编写Helper, 根据symfony中helper的命名规则创建文件如下

$cd pathtoproject/plugins/QRcodePlugin/lib/helper

$vi QRcodeHelper.php

<?php
# [useage]
# qr_img.php?d=[data]&e=[(L,M,Q,H)]&s=[int]&v=[(1-40)]
# (&m=[(1-16)]&n=[(2-16)](&p=[(0-255)],&o=[data]))
#
# d= data URL encoded data.
# e= ECC level L or M or Q or H (default M)
# s= module size (dafault PNG:4 JPEG:8)
# v= version 1-40 or Auto select if you do not set.
# t= image type J:jpeg image , other: PNG image
#
# structured append m of n (experimental)
# n= structure append n (2-16)
# m= structure append m (1-16)
# p= parity
# o= original data (URL encoded data) for calculating parity
#
function QRcode($d, $e = 'M', $s = null, $v = null, $t = 'P', $m = null, $n = null, $o = null, $p = null)
{
$path = '/QRcodePlugin/qr_img/php/qr_img.php';
$url = $path . '?d=' . $d;
if ($e && in_array(strtoupper($e), array('L', 'M', 'Q', 'H'))) {
$url .= '&e=' . strtoupper($e);
} else {
$url .= '&e=M';
}
if ($s) {
$url .= '&s=' . $s;
}
if ($v) {
$url .= '&v=' . $v;
}
if ($t) {
$url .= '&t=' . $t;
}
if ($m) {
$url .= '&m=' . $m;
}
if ($n) {
$url .= '&n=' . $n;
}
if ($o) {
$url .= '&o=' . $o;
}
if ($p) {
$url .= '&p=' . $p;
}
$output = image_tag($url, array('alt' => $d));
return $output;
}

这样, 我们就写好了一个只有一个Helper的Plugin, 我们来看一下插件结构如下.
|--.lib
|...`--.helper
|.......`--.QRcodeHelper.php
`--.web
....`--.qr_img
........|--.data
........|--.image
........`--.php
............`--.qr_img.php
创建symfony插件》一文中我们说过项目中是无法直接访问plugin中的web目录的, 所以我们还要copy一份web目录到项目的web目录下
$cp -rf pathtoproject/plugins/QRcodePlugin/web pathtoproject/web/QRcodePlugin接下来我们来测试一下Plugin是否有效.
$cd pathtoproject/$./symfony init-app test$./symfony init-module test test$vi apps/test/modules/test/actions/actions.class.php<?php
class testActions extends sfActions
{
public function executeIndex(sfWebRequest $request) { }
}

$vi apps/test/modules/test/templates/indexSuccess.php<?php use_helper('QRcode');?>
<?php echo QRcode('fuck');?>

访问http://project/test.php/test/index效果如下:

screenshot4

源代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.css" />
</head>
<body>
<img alt="fuck" src="/QRcodePlugin/qr_img/php/qr_img.php?d=fuck&t=P" /> 
</body>
</html>

测试通过, 本文完.

创建symfony插件

symfony是一款支持插件机制的php框架, 在使用symfony开发项目的时候可以很方便的从官方(http://www.symfony-project.org/plugins)下载到由其他开发者贡献出来的插件.

关于插件的使用请参考 http://www.symfony-project.org/book/1_2/17-Extending-Symfony#Plug-Ins

当使用symfony一段时间后, 我们可能有很多可以重用的代码, 为了方便以后重用, 我们可以将这些代码创建成插件, 甚至可以发布到官方的插件库中提供他人下载使用.

symfony1.2中插件位于项目根目录的plugins目录下, symfony1.2的插件的目录结构如下:

|--.LICENSE
|--.README
|--.config
|...|--.app.yml
|...|--.cache.yml
|...|--.routing.yml
|...|--.schema.yml
|...|--.security.yml
|...|--.settings.yml
|...|--.pluginNamePluginConfiguration.class.php
|...`--.view.yml
|--.doc
|--.i18n
|--.log
|--.lib
|...|--.filter
|...|--.form
|...|--.helper
|...|--.model
|...|--.task
|...|--.validator
|...`--.widget
|--.modules
|...`--.testPlugin
|.......|--.actions
|.......|...`--.actions.class.php
|.......|--.config
|.......`--.templates
|...........`--.indexSuccess.php
|--.templates
|...`--.layout.php
|--.test
`--.web
....|--.css
....|...`--.main.css
....|--.images
....|--.js
....|--.robots.txt
.....`--.uploads
........`--.assets

目录结构很清晰, 虽然目录很文件很多但都不是必须的, 你只需要编写你要扩展的那部分文件就可以了.在插件中我们可以象在项目中一样自动加载config, 编写action和template, 自动加载lib等等.

如果我们想写一个helper插件, 那么我们只要建立一个lib目录和一个/lib/helper目录, 并将helper放在helper目录下就可以使用了.

如果你要扩展一个动作, 那你只需要象平常一样修改mudules目录, 修改你要使用该动作的app的settings.yml如下:

/apps/frontend/config/settings.yml
enabled_modules: [default, pluginModuleName]

然后你就可以通过http://project/frontend_dev.php/pluginModuleName/index访问到插件中的动作了.

插件中的web目录是比较特殊的, 由于symfony独特的目录结构, 你并不可能直接访问到plugin的web目录, 在安装plugin的过程成, symfony会自动将插件中的web目录copy到项目的web目录下, 并以plugin命来重命名plugin的web目录, 所以如果你想你访问你自己编写的插件中的web目录也要将web目录copy到项目的web目录下并重新命名.

参考: http://www.symfony-project.org/jobeet/1_2/Propel/en/20