什么是Bundle
- Bundle在你的项目里是一等公民
- 事实上SF2本身就是一个Bundle
- 最小程度的粘合剂 用于集成类库/命令行工具到SF2
Bundle能干啥哟
- 提供控制器 example: Controller
- 提供命令行 example: app/console command tool
- 提供ORM实体(Entities)或者文档(Documents)
- 提供服务(Services)
- 提供Assets文件(js css img)
第三方Bundles的索引: knpbundles.com (其实我更喜欢packagist.org)
自动索引类似Bundle的代码
遵循下面的这些规则 会给bundle生成一定的分数
- 每新增一个github的followers都有加分 (+1分)
- README.md超过300个字也能加分 (+5分)
- 如果使用CI持续集成也能加分 (+5分)
- 如果travisCI上build的status都是ok的加分 (+5分)
- 提供composer包的加分 (+5分)
- 在KnpBundles每有一个人推荐你的bundle加分 (+5分)
- 每个月都最少要在github上提交一次
Knpbundles索引大全长啥样
(其实packagist.org更好用:))
小哥 如果你有天心血来潮要写自己的bundle 请先上knp跟packagist看看是不是已经有了类似的bundle 有的话 请fork它 帮助它改善的更稳定更强大 这样能节约你的时间
Bundle开发最好的实践 : Bundle的目录结构
AcmeMyBundle.php
Command
MyCommand.php
Controller
MyController.php
Doctrine
ORM
Foo.php
FooRepository.php
Model
Foo.php
Resources
config
doc
meta
public
views
...
参考CMF : Bundle Standards
Bundle开发最好的实践 : DIC 设置
- 所有的service前缀都用Bundle的别名 (eg : AcmeMyExtension::getAlias() )
- 任何参数都显式处理
- 使用compiler传递对其它Bundle服务的作用
DependencyInjection Compiler MyCompilerPass.php Configuration.php AcmeMyExtension.php
use Symfony\C..\D..I..\ContainerBuilder as CB;
use Symfony\C..\Config\FileLocator;
use Symfony\C..\HttpKernel\D..I..\Extension;
use Symfony\..\D..I..\Loader\XmlFileLoader;
class AcmeMyExtension extends Extension
{
public function load(array $configs, CB $dic)
{
$configuration = new Configuration();
$config = $this->processConfiguration(
$configuration, $configs
);
$dir = __DIR__ . '/../Resources/config';
$locator = new FileLocator($dir);
$loader = new XmlFileLoader($dic, $locator);
$loader->load('services.xml');
foreach ($config as $key => $val) {
$dic->setParameter('acme_my.'.$key, $val);
}
}
}
Bundle开发最好的实践 : 设置一个class
- 合并同时验证Bundle的设置参数
- Sf2.1+ : app/console config:dump-reference
use Symfony\C..\Config\Definition as Def;
class Configuration implements Def\ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new Def\Builder\TreeBuilder();
$treeBuilder->root('acme_my')
->children()
->scalarNode('host')
->isRequired()->cannotBeEmpty()->end()
->scalarNode('port')
->defaultValue(2000)->end()
->scalarNode('timeout')
->defaultValue(30000)->end()
->end()
;
return $treeBuilder;
}
}
Bundle开发最好的实践 : Composer包设置
- 用packagist创建你的composer索引
- Bundle要在packagist上注册过
- 确定开启了packagist提交钩子
{
"name": "acme/my-bundle",
"type": "symfony-bundle",
"description": "This Bundle is an example",
"license": "MIT",
"authors": [
{
"name": "Duffy Duck",
"email": "diffy@acme.com"
}
],
"require": {
"php": ">=5.3.3",
"symfony/framework-bundle": "~2.2",
},
"autoload": {
"psr-0": { "Acme\\MyBundle": "" }
},
"target-dir": "Acme/MyBundle"
}
Bundle开发最好的实践 : 测试
- JMSCommandBundle可以生成函数式测试的kernel代码
- 测试
Controller
MyControllerTest.php
Functional
HomepageTest.php
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class HomepageTest extends WebTestCase
{
public function testContents()
{
$client = $this->createClient();
$crawler = $client->request('GET', '/');
$s = $client->getResponse()->getStatusCode();
$this->assertEquals(200, $s);
$crawler->filter('h1:contains(Homepage)');
$this->assertCount(1, $count);
$crawler->filter('ul.menu_main li')
$this->assertCount(13, $count);
}
}
Bundle开发最好的实践 : 持续集成 travisCI
- 项目根目录下创建.travis.yml文件
- 开启github钩子来自动测试
- 多个版本的PHP,类库,数据库的测试
- fork这个项目之后可以很简单的测试
language: php
php:
- 5.3
- 5.4
- 5.5
env:
- SYMFONY_VERSION=2.2.*
- SYMFONY_VERSION=2.3.*
- SYMFONY_VERSION=dev-master
before_script:
- composer require symfony/symfony:${SYMFONY_VERSION} --prefer-source
- vendor/symfony-cmf/testing/bin/travis/phpcr_odm_doctrine_dbal.sh
script: phpunit --coverage-text
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。