sobipro是joomla上的CCK组件,之所以会有这样的组件是因为joomla并没有为内容添加字段的功能,joomla虽然是CMS,但它的内容组件可定制性十分弱,内容表现性并不丰富,所以不得不依赖第三方CCK组件。而sobipro是joomla cck组件中算得上比较专业的一款。
说它专业,除了它有强大的内容管理功能之外还有可扩展性,可以根据实现需要购买与下载官方提供的扩展模块,代码质量与稳健性也不错。但我在对它进行二次开发时发现了不少问题,往往会导致开发效率低下。以下是我总结的几点。
基于joomla框架之上再建框架,而官方并没有开发文档
joomla由于joomla1.5至joomla2.5过渡框架差异比较大,而且joomla框架提供的架构也不够灵活,所以不少组件会在joomla之上再建造兼容框架,为了可以同时兼容joomla新旧版本。而sobipro虽然也是MVC结构,但与joomla框架差异很大如果官方没有提供开发文档,只凭自己消耗时间阅读代码。
├─base
│ └─fs
├─cms (joomla兼容层)
│ ├─joomla15
│ │ ├─base
│ │ └─html
│ ├─joomla16
│ │ ├─base
│ │ ├─elements
│ │ └─html
│ └─joomla_common
│ ├─base
│ ├─elements
│ └─html
├─ctrl (控制器)
│ └─adm
├─env
├─helpers (辅助)
│ └─adm
├─js
│ ├─adm
│ ├─calendar
│ │ └─lang
│ └─codemirror
├─mlo
├─models (模型)
│ ├─adm
│ └─fields
├─plugins (插件)
├─services
│ └─installers
│ └─schemas
├─types
└─views (视图)
└─adm
模板使用xslt
我第一次使用xslt就是在sobipro上,才知道xslt有多么难用,语法冗长、模板不灵活、调试难度大等问题严重影响开发效率。假设你只需要小修改它的模板,你必须先学习xslt语法,以下是我做一个动态链接的代码
<a class="field_positon_ordering" href="{$url}&ordering=field_position.asc">
<xsl:if test="contains($ordering_classes, 'field_position') and contains($ordering_classes, 'asc')">
<xsl:attribute name="href">
<xsl:value-of select="concat($url, '&ordering=field_position.desc')" />
</xsl:attribute>
</xsl:if>
Position <small class="arrow"></small>
</a>
这仅仅只是改模板,如果你需要添加一些数据属性,而XML并没有输出,那你只能修改view层给它添加数据,以下是sobipro输出XML之前的部分代码
$data[ 'name' ] = array(
'_complex' => 1,
'_data' => $this->get( 'listing_name' ),
'_attributes' => array( 'lang' => Sobi::Lang( false ) )
);
if( Sobi::Cfg( 'category.show_desc' ) ) {
$desc = $current->get( 'description' );
if( Sobi::Cfg( 'category.parse_desc' ) ) {
Sobi::Trigger( 'prepare', 'Content', array( &$desc, $current ) );
}
$data[ 'description' ] = array(
'_complex' => 1,
'_cdata' => 1,
'_data' => $desc,
'_attributes' => array( 'lang' => Sobi::Lang( false ) )
);
}
$data[ 'meta' ] = array(
'description' => $current->get( 'metaDesc' ),
'keys' => $this->metaKeys( $current ),
'author' => $current->get( 'metaAuthor' ),
'robots' => $current->get( 'metaRobots' ),
);
$data[ 'entries_in_line' ] = $this->get( '$eInLine' );
$data[ 'categories_in_line' ] = $this->get( '$cInLine' );
这只是很小的一部分,其它简直是不知所云。如果官方有文档提供,这里的数据属性应该会比较好理解。
只是这种难度可能对于大多数人来是可以接受的,但你还得先找到你所见页面的view层在哪里,因为它真的很难找。joomla一般可以通过URL找到对应代码
index.php?option=com_content&view=article&id=1788
以上地址很容易可以知道代码在components/com_content/views/article/view.html.php
但sobipro并不总是这样,例如这个地址
index.php?option=com_sobipro&sid=5980
这个页面是分类列表页?分类页?内容页?都可能是!sobipro把三大数据类型section, category, content都叫entity,并且放在同一个数据表中,而且都用sid作为主键。所以你给它一个sid,它先在数据库查这个entity是什么类型,如果是category,就会给你category的Controller, Model, View, template。而因为这三大类型具有许多相同属性,所以它们的MVC是会放上继承的。例如category的view层其实是使用了section的view层,找起来像面条似的,你不做一些标记很容易会漏掉。幸好它只有这三种层次,所以我给所有的view层都加debug代码还是能找出来的,只是debug信息它都会屏敝。也由于输出是XML再用xslt转为HTML,像var_dump这样粗暴的方法会直接破坏xml代码,让xslt转换失败直接给你反馈空白页。sobipro改错一点就出现空白页,所以很难知道是什么原因导致的。
数据查询
joomla2开始已经有CRUD可用了,不像joomla 1.5需要写SQL。但如果要兼容新旧版本就可能需要再造CRUD的轮子。但造轮子也不至于这么难看吧
$table = $db->join(
array(
array( 'table' => 'spdb_field_option_selected', 'as' => 'opts' ),
array( 'table' => 'spdb_language', 'as' => 'lang', 'key' => array( 'opts.optValue', 'lang.sKey' ) ),
array( 'table' => 'spdb_object', 'as' => 'spo', 'key' => array( 'opts.sid', 'spo.id' ) ),
array( 'table' => 'spdb_relations', 'as' => 'sprl', 'key' => array( 'opts.sid', 'sprl.id' ) ),
)
);
try {
$db->select( $oPrefix . 'id', $table, $conditions, $eOrder, $eLimit, $eLimStart, true );
$results = $db->loadResultArray();
}
catch ( SPException $x ) {
Sobi::Error( 'AlphaListing', SPLang::e( 'DB_REPORTS_ERR', $x->getMessage() ), SPC::WARNING, 0, __LINE__, __FILE__ );
}
这样的数据操作代码比SQL丑太多了,填一堆array的出错率高得很。不喜欢它可以使用joomla原生的查询方法,但二次开发情况有复杂,直接修改它会比重新写要稳定得多。特别是很多时候你不得不修改插件。
MVC层次组织不合理
一般C层作为入口都代表页面或者功能入口,但sobipro而数据类型为入口,我真不知道这种层次有什么优点,但缺点倒是不少。例如alpha插件(字母列表)只不过在原来的分类列表页加上字母筛选,用的都是同一套template,但alpha的M层竟然需要仿照分类页的M层重写一次,也就是我如果在列表页上添加新功能,我就需要在alpha插件再加一次。那是因为alpha不能复用M层,不得不在C层写SQL代码,并且还是很近似的代码,这样做成MVC有何用?
结论
sobipro如此美丽又专业的外观,却隐藏如此不合理的设计,但这在joomla的扩展群里是个普遍现象,好看不好使,好使不好改,sobipro也已经是其中做得不错的一个组件了,建议在做joomla二次开发时最好不要做太复杂的功能,也许简单的修改你都有可能改到吐血。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。