- 新建项目没有规范,随手拷贝已有项目已成"乱象"
- 已有项目对框架侵入严重,每个项目的框架代码都不相同
- 基于复制粘贴复制公共库,代码不一致,无法统一升级更新,效率低下
- 统一项目脚手架:命令一键创建新项目
- 统一基础公共库:命令一键安装与更新依赖
- composer satis + gitlab 私有仓库搭建
- composer工具培训
- 脚手架接入composer仓库
- 图片处理、link处理等常见痛点封装为公共库,接入composer仓库
基于composer+gitlab搭建整套架构,其中composer类似于java maven、python pip、nodejs npm,是一款可靠的php包管理工具。
composer cli <--- packagist.baidu.com <--- gitlab-team.baidu.com
- 客户端:composer完成依赖配置、安装、更新
- 私有仓库:composer satis搭建,仅维护私有包的索引信息
- 代码托管:gitlab,存储库代码,维护分支与tag
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
安装成功后,可以直接使用composer命令。
使用Windows的同学可以通过Phpstorm直接安装与管理composer。
执行composer init来初始化一个空白项目,也称为"root项目"。
composer init
Welcome to the Composer config generator
This command will guide you through creating your composer.json config.
Package name (<vendor>/<name>) [owenliang/myproject]:
根据提示填入各种信息即可,最终会生成composer.json配置文件。
生成后的composer.json文件如下:
{
"name": "owenliang/myproject",
"authors": [
{
"name": "owenliang",
"email": "120848369@qq.com"
}
],
"require": {}
}
作为root项目,通常只关心自己依赖哪些包、包的版本是什么。
默认composer只会在官方仓库中寻找你要安装的包,例如安装一个elasticsearch的客户端:
composer require 'ongr/elasticsearch-dsl:^5.0'
包的命名遵循:"组织名/包名",是全局唯一的,冒号之后是版本控制,具体规则后面会提供学习链接。
安装这样的第三方包不需要做额外的配置,composer工具总是会到官方仓库中寻找你要安装的包。
现在composer.json如下:
{
"name": "owenliang/myproject",
"authors": [
{
"name": "owenliang",
"email": "120848369@qq.com"
}
],
"require": {
"ongr/elasticsearch-dsl": "^5.0"
}
}
安装私有仓库的包略有不同,首先需要配置composer私有库的地址,编辑上述composer.json:
{
"name": "owenliang/myproject",
"authors": [
{
"name": "owenliang",
"email": "120848369@qq.com"
}
],
"require": {
"ongr/elasticsearch-dsl": "^5.0"
},
"repositories": [{
"type": "composer",
"url": "http://packagist.baidu.com"
}],
"config": {
"secure-http": false
}
}
现在尝试安装一个私有的包:
composer require 'baidu/common:^1.0'
composer工具会到私有仓库查找这个包,如果没找到还会去默认的官方仓库查找。
未来可以移除secure-http选项,因为最终私有仓库域名会改为https协议。
- 初始化composer.json:
composer init
- 安装依赖
composer require "组织名/库名:版本控制"
- 删除依赖
composer remove "组织名/库名"
- 升级依赖(先修改composer.json中的依赖配置)
composer update
- 清空缓存
composer clearcache
composer安装的包文件存储在vendor目录。
为了在自己的项目中使用安装的依赖库,需要加载composer的autoload函数,这样才能访问到包中的类和方法:
<?php
require_once __DIR__ . "/vendor/autoload.php";
<?php
require_once __DIR__ . "/vendor/autoload.php";
use baidu\common\Author;
Author::name();
baidu\common\Author类会被自动加载到PHP中,这里调用了它的静态方法name()。
下面介绍如何制作一个composer包,最终制作好的包既可以发布到公共仓库,也可以发布到私有仓库。
我最终希望发布包到composer私有仓库,所以包的代码也托管在私有的gitlab中才安全。
在gitlab上创建一个叫做php-common的项目。
希望发布一个包叫做"baidu/common",因此我们依旧通过composer init来初始化一个composer.json:
{
"name": "baidu/common",
"description": "common utility for php team",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "owenliang",
"email": "owenliang@baidu.com"
}
],
"minimum-stability": "stable",
"require": {}
}
该包当然也可以通过require来依赖其他的包,即二级依赖。
composer包名是name指定的,与gitlab项目名无关。
composer包建议把源代码放在src目录下:
owenliangs-MacBook-Pro:php-common owenliang$ ll src/
total 8
-rw-r--r-- 1 owenliang staff 120 5 7 12:39 Author.php
我希望整个包下的所有class文件,均采用baidu\common的命名空间前缀。
以src/Author.php为例:
<?php
namespace baidu\common;
class Author
{
public static function name() {
return 'baidu@2018';
}
}
为了composer可以找到加载到baidu\common\Author这个类,需要在composer.json中定义"命名空间前缀"与"类文件路径"之间的关系。
{
"name": "baidu/common",
"description": "common utility for php team",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "owenliang",
"email": "owenliang@baidu.com"
}
],
"minimum-stability": "stable",
"require": {},
"autoload": {
"psr-4": {
"baidu\\common\\": "src"
}
}
}
我们遵循psr-4类加载规范,以baidu\common命名空间为前缀的class,会在src目录下查找。
当其他项目调用baidu\common\Author类时,composer会在"vendor/baidu(组织名)/common(包名)/src/"下加载Author.php文件。
composer建议把测试代码放在test目录下:
owenliangs-MacBook-Pro:php-common owenliang$ ll test/
total 8
-rw-r--r-- 1 owenliang staff 167 5 7 10:25 test_Author.php
我编写一个很简单的调用示例:
<?php
require_once __DIR__ . "/../vendor/autoload.php";
if (\baidu\common\Author::name() == 'baidu') {
printf("success\n");
} else {
printf("fail\n");
}
就像其他项目一样,我们引入composer的autoload,然后就可以访问对应的类。
satis用于构建一个私有仓库,它通过扫描gitlab上的版本库信息建立仓库索引,并将索引提供给composer客户端获取。
代码最终依旧是客户端直接向gitlab下载的,相关的权限验证依旧由gitlab把控。
composer create-project composer/satis:dev-master --keep-vcs
在satis目录下放置一个satis.json配置文件,在其中罗列所有gitlab上希望发布的包信息:
{
"name": "Private Repository",
"homepage": "http://packagist.baidu.com",
"repositories": [
{
"type": "git",
"url": "https://gitlab-team.baidu.com/baidu/php-common"
}
],
"require": {
"baidu/common": "*"
}
}
- name: 私有仓库的名字,最终会展现在UI界面上
- homepage: 私有仓库的服务地址,未来会替换为https协议
- repositories:所有要发布的包地址
- require: 指定索引哪些包的哪些版本,这里我指定索引baidu/common包的所有版本。
千万不要使用require-all选项,而是应该在require中罗列每个包(require-all的意思是将官方仓库的所有包索引到本地,对我们毫无意义)。
因为我的gitlab采用帐号密码认证,所以需要为composer配置gitlab帐号密码:
composer config -g http-basic.gitlab-team.smzdm.com liangdong baidu@123
帐号密码被保存在~/.composer/auth.json中。
satis只是一个命令行工具,我们需要定时让satis扫描gitlab上的版本变化,更新仓库索引信息。
将下面的任务添加到crontab(非root用户):
flock -xn /tmp/satis.lock -c '/usr/local/bin/php /data/webroot/phpsrc/satis/bin/satis build /data/webroot/phpsrc/satis/satis.json /data/webroot/phpsrc/satis/repo'
该命令可以防止并发执行多个satis,同时会将构建好的静态索引文件存储到repo目录。
实际上仓库就是一个索引文件package.json文件,它描述了完整的gitlab包索引信息:
{
"packages": {
"baidu/common": {
"1.0.0": {
"name": "baidu/common",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://gitlab-team.baidu.com/baidu/php-common",
"reference": "91266fd41e3755794f4eb16d4d5f3cde44ca7649"
},
"time": "2018-05-07T03:41:48+00:00",
"type": "library",
"autoload": {
"psr-4": {
"baidu\\common\\": "src"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "owenliang",
"email": "owenliang@baidu.com"
}
],
"description": "common utility for php team"
},
"1.0.1": {
"name": "baidu/common",
"version": "1.0.1",
"version_normalized": "1.0.1.0",
"source": {
"type": "git",
"url": "https://gitlab-team.baidu.com/baidu/php-common",
"reference": "ff8fbe09faa384ebcdc57db9d63cc8dc78a1dc39"
},
"time": "2018-05-07T04:39:28+00:00",
"type": "library",
"autoload": {
"psr-4": {
"baidu\\common\\": "src"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "owenliang",
"email": "owenliang@baidu.com"
}
],
"description": "common utility for php team"
},
"dev-master": {
"name": "baidu/common",
"version": "dev-master",
"version_normalized": "9999999-dev",
"source": {
"type": "git",
"url": "https://gitlab-team.baidu.com/baidu/php-common",
"reference": "ff8fbe09faa384ebcdc57db9d63cc8dc78a1dc39"
},
"time": "2018-05-07T04:39:28+00:00",
"type": "library",
"autoload": {
"psr-4": {
"baidu\\common\\": "src"
}
},
"license": [
"MIT"
],
"authors": [
{
"name": "owenliang",
"email": "owenliang@baidu.com"
}
],
"description": "common utility for php team"
}
}
}
}
- dev-master:非stable的开发中master分支
- 1.0.0:stable版本
- 1.0.1:stable版本,修复了1.0.0版本中的一些问题
为了让composer客户端可以访问到私有仓库的索引,以及为了有一个可视化的界面查看索引,我们需要配置nginx指向repo目录:
server {
listen 80;
server_name packagist.baidu.com;
root /data/webroot/phpsrc/satis/repo;
charset utf-8;
access_log off;
}
打开浏览器访问http://packagist.baidu.com即可看到所有被索引的包与版本信息。
我们可以将一份标准模板web框架上传到gitlab项目中,并将项目发布为一个composer包。
我们知道,composer require命令安装的包都会被存储到vendor目录下,并提供autoload自动加载。
除此之外,其实composer还提供了create-project命令,它专门用于创建模板项目。
它的工作原理是:
- git clone直接下载包代码到当前目录
- composer update下载模板项目的依赖包
- 执行composer.json中配置的一些钩子函数,做一些自定义操作(比如创建目录)
这个过程我们可以手动操作,只是composer更方便:
composer create-project 'baidu/common' my-common --stability=stable --repository 'http://packagist.baidu.com' --no-secure-http --remove-vcs
上述命令将baidu/common项目下载到本地的my-common目录,需要指定仓库地址为我们的私有仓库,并且下载完成后删除.git目录。
主流的PHP开源框架均采用composer来帮助开发者初始化项目,一般思路如下:
- 框架核心模块分别独立发布在多个composer包里
- 框架脚手架发布单独的composer包,预建了controller、model等目录,并配置composer.json定义二级依赖各个独立的框架核心包
- 使用脚手架的用户可以通过composer update一键更新所有框架核心代码,实现了业务与框架的分离
satis会自动识别gitlab上的分支与tag。
作为tag发布的版本均被composer视为stable稳定版本,例如1.0.0,1.0.1的tag会被Composer索引为1.0.0与1.0.1。
在普通分支中的代码是非stable(非稳定)版本,composer会在索引时在它们的分支名前增加dev-前缀,例如master分支的composer版本为dev-master。
我们总是应该依赖stable版本,而不是依赖一个开发中的dev-master版本。
另外,简单解释一下语义化版本a.b.c:
- a:主版本,一般与前一个主版本存在不兼容的功能
- b:次版本,发布的功能能够向下兼容
- c:补丁版本:修复现有功能问题