原文http://blog.xebia.com/2013/09/01/differences-between-providers-in-angularjs/

什么是Provider

AngularJS官方文档定义:

A provider is an object with a $get() method.
The injector calls the $get method to create a new instance of a service.
The Provider can have additional methods which would allow for configuration of the provider.

AngularJS使用$provide 来注册新的provider. 每个Provider只进行一次实例的创建。

$provide 有六个方法来创建定制化的Provider:

  • constant
  • value
  • service
  • factory
  • decorator
  • provider

constant

constant能够被注入到任何地方。constant不能被装饰器拦截,这意味着contant的值将永远无法改变。

var app = angular.module('app', []);

app.config(function($provide){
    $provide.constant('movieTitle', 'The Matrix');
});

app.controller('ctrl', function(movieTitle){
    expect(movieTitle).toEqual('The Matrix');
});

AngularJs提供一种更加简便的方式创建constant:

app.constant('movieTitle', 'The Matrix');

value

value只是一个简单的可注入的值,这个值可以是字符串、数字和方法。和constant不同的是它不能够被注入到配置,但是能够被装饰器拦截。

var app = angular.module('app', []);

app.config(function($provide){
     $provide.value('movieTitle', 'The Matrix');
});

app.controller('ctrl', function(movieTitle){
    expect(movieTitle).toEqual('The Matrix');
});

AngularJs提供一种更加简便的方式创建value:

app.value('movieTitle', 'The Matrix');

service

service 是一个可注入的构造函数。你可以在函数中指定依赖。service是单例的,只被anguarJs创建一次。service是一个非常棒的方法来进行controller之间的通信,例如共享数据.

var app = angular.module('app', []);

app.config(function($provide){
    $provide.service('movie', function(){
        this.title = 'The Matrix';
    });
});

app.controller('ctrl', function(movie){
    expect(movive.title).toEequal('The Matrix');
});

AngularJs提供一种更加简便的方式创建service:

app.service('movieTitle', function(){
    this.title = 'The Matrix';
});

Factory

factory是一个可注入的方法。从某种的意义而言factory非常像service,它也是单例的同样能够在函数中定义依赖。两者不同的是,factory注入是一个plain function,所以angularjs能够执行该方法,而service注入的是一个构造函数。当去new一个serivce的时候,构造函数创建一个新的对象。但是使用factory你可以让函数返回任何东西。

稍后你会看见,factory仅仅是一个拥有 $get 方法的provider。

var app = angular.module('app', []);

app.config(function($provide){
    $provide.factory('movie', function() {
        return {
            title: 'The Matrix'
        };
    });
});

app.controlller('ctrl', function(movie){
    expect(movive.title).toEequal('The Matrix');
});

AngularJS还提供一种更加简便的方法:

app.factory('movie', function() {
    return {
        title: 'The Matrix'
    };
});

Decorator

decorator能够修改和压缩其他provider,正如上面提到的constant是一个列外。

var app = angular.module('app', []);

app.value('movieTitle', 'The Matrix');

app.config(function($provide){
    $provide.decorator('movieTitle', function($delegate){
        return $delegate + ' - starring Keanu Reeves'
    });
});

app.controller('myCtrl', function(movieTile){
    expect(movieTitle).toEqual('The Matrix - starring Keanu Reeves');
});

Provider

provide在所有的provider中是最复杂的方法,它允许你创建一个复杂的功能和配置选项.

provide 实际上是一个配置的factory.它可以是一个对象或者构造函数。

var app = angular.module('app', []);

app.provider('movie', function(){
    var version;
    return {
        setVersion: function(value) {
            version = value;
        },
        $get: function() {
            return {
                title: 'The Matrix' + ' ' + version
            }
        }
    };
});

app.config(function(movieProvider){
    movieProvider.setVersion('Reloaded');
});

app.controller('ctrl', function(movie) {
    expect(movie.title).toEqual('The Matrix Reloaded');
});

总结

  • 所有的provider只被实例化一次,它们全是单例的。
  • 除了constant的所有provider都能够被装饰
  • constant是一个能被注入到任何地方的值,而且不能被修改
  • value只是一个简单能被注入的值
  • service是一个能被注入的构造方法
  • factory是一个能被注入的函数
  • decoratory能够修改压缩除了constant的其他provider
  • provider是一个可配置的facotry

创建一个文件夹test,并创建一个新文件uppercaseme.js

1
2
3
4
5
6
7
8
9
10
11
// uppercaseme.js
"use strict"
var fs = require('fs');
var myfile = "myfile.txt";
if(fs.existsSync(myfile)) {
var content = fs.readFileSync(myfile, 'utf8');
fs.writeFileSync(myfile, content.toUpperCase());
console.log("Done");
} else {
console.log("File does not exist - " + myfile);
}

代码的目的是读取myfile.txt并转化内容为大写。

(执行:)

1
node uppercaseme

执行命令行命令时需在同一个目录

在命令行可以查看输出,并得知是否执行成功。

使用命令行参数

上一个列子将读取的文件hardcoding了,我们稍作改进,通过命令行读取要执行操作的文件。

1
2
3
4
//使用process.argv
0: node
1: <name-of-your-js-file>
2+....<additional arguments passed>

更新代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"use strict"
var fs = require('fs');
if(process.argv.length > 2) {
// Read the first additional argument passed to the program
var myfile = process.argv[2];

if(fs.existsSync(myfile)) {
var content = fs.readFileSync(myfile, 'utf8');
fs.writeFileSync(myfile, content.toUpperCase());
console.log("Done");
} else {
console.log("File does not exist - " + myfile);
}
} else {
console.log("ERROR: Pass on a file name/path");
}

代码做了简单的判断,当我们没有获取到输入的文件名时,抛出错误。

(执行:)

1
node uppercaseme myfile.txt

创一个Node模块

将我们写好的模块发布出来,让更多人使用,发布之后其他人就可以像下面一样使用:

  • 通过NPM安装
1
npm install uppercase
  • 在命令行中使用
1
uppercaseme <filename>
  • 被当作模块在其他模块中使用
1
require('uppercaseme');

为了做到以上的效果,我们将会创建一个NPM包

  1. 首先我们需要做的是改变目录结构
1
2
3
4
5
6
7
8
9
10
test
src
-- bin
-- uppercaseme
-- lib
-- uppercaseme.js
-- package.json
-- README.md

myfile.txt

将我们刚刚写好的uppercaseme.js移动到lib目录。其他文件先留空在接下来进行完善。

(命令行仍然在test文件夹)

1
node ./src/lib/uppercaseme ./myfile.txt

和之前的运行效果相同。

  1. 接下来创建 src/bin/uppercaseme

请注意这个文件没有扩展名

1
2
3
4
5
6
7
8
#!/usr/bin/env node

"use strict";
var path = require('path');
var fs = require('fs');
var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');

require(lib + '/uppercaseme.js').convert();
  1. 改造文件为Node模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
"use strict"
var fs = require('fs');
function convertThis() {
if(process.argv.length > 2) {
var myfile = process.argv[2];

if(fs.existsSync(myfile)) {
var content = fs.readFileSync(myfile, 'utf8');
fs.writeFileSync(myfile, content.toUpperCase());
console.log("Done");
} else {
console.log("File does not exist - " + myfile);
}
} else {
console.log("Pass on a file name/path");
}
}
exports.convert = convertThis;

暴露出convert接口

现在在进行测试,将会和之前效果相同

node ./src/bin/uppercaseme ./myfile.txt

创建NPM包

  1. 创建 src/package.json 和 src/README.md

package.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"author": "authoer",
"name": "uppercaseme",
"description": "Converts files to uppercase",
"version": "0.0.1",
"repository": {
"url": ""
},
"main": "./lib/uppercaseme",
"keywords": [
"upper",
"case",
"file"
],
"bin": {
"uppercaseme": "./bin/uppercaseme"
},
"dependencies": {},
"engines": {
"node": "*"
}
}

main是一个模块的ID,也是程序的主要入口。在例子中我们的package被命名为 uppercaseme 。当用户安装之后,并 require(‘uppercaseme’)之后我们的主模块的export object会被返回。

bin 我们会通过命令行在任何地方运行,安装之后,npm全局安装后会创建 bin/uppercaseme的符号链接,或者 ./node_modules/.bin/ 本地安装

dependencies 我们package的所需的依赖列表

  1. 发布

在发布之前,必须有一个user。如果没有:

npm adduser

提供你的用户名和邮件地址,会为你新建一个用户。

假设你仍然在 test 目录,请执行:

cd src
npm publish

提示成功,则表明你已经成功发布一个NPM package

安装我们的NPM包

切换到其他目录,并输入命令:

npm install uppercaseme

这将会获取 uppercaseme 包,并创建一个本地安装。这只是一个本地安装,我们并不能在任何地方使用。
这个命令会在目录创建一个 node_modules 目录,我们的 uppercaseme 模块就安装在此。并且在 .bin 中创建了一个链接。

接下来进行测试:

echo 'my lowercase file' > myfile.txt

使用我们的模块进行转化:

./node_modules/.bin/uppercaseme myfile.txt

OR

"./node_modules/.bin/uppercaseme" myfile.txt

检查执行之后的文件,是否被成功转化。

接下来进行全局安装,在这之前先将本地安装卸载:

npm uninstall uppercaseme

这将会把我们的模块在node_modules中移除。

现在我们来进行全局安装:

npm install -g uppercaseme

安装成功后,我们可以在任何目录进行操作:

uppercaseme myfile.txt

参考文章

[note]

在package.json所在目录下使用npm install . -g可先在本地安装当前命令行程序,可用于发布前的本地测试。

  • 检查是否安装svn

    1
    $rpm -qa subversion
  • 卸载旧版本的svn

    1
    $yum remove subversion
  • 安装需要的apache模块

1
2
3
4
5
$yum install mod_dav_svn mod_auth_mysql
//确认是否安装
$ls /etc/httpd/modules | grep svn
mod_authz_svn.so
mod_dav_svn.so
  • 验证安装
1
2
3
4
5
6
7
8
9
10
11
12
13
$svnserve --version
svnserve,版本 1.6.11 (r934486)
编译于 Jun 23 2012,00:44:03
版权所有 (C) 2000-2009 CollabNet。
Subversion 是开放源代码软件,请参阅 http://subversion.tigris.org/ 站点。
此产品包含由 CollabNet(http://www.Collab.Net/) 开发的软件。

下列版本库后端(FS) 模块可用:

* fs_base : 模块只能操作BDB版本库。
* fs_fs : 模块与文本文件(FSFS)版本库一起工作。

Cyrus SASL 认证可用。

以上的配置参考CentOS-6.3安装配置SVN

配置apache


由于我的服务器80端口被nginx占用,所以采用nginx反向代理的办法,apache监听8080端口,
配置nginx

1
proxy_pass http://127.0.0.1:8080

配置svn用户密码

设置密码

1
$sudo htpasswd -c /opt/svn/passwd abc

创建用户abc并按照提示设置密码,网页认证的时候使用该用户名和密码登录。后面再添加用户的时候去掉-c选项。

*初始化版本仓库,导入原始代码

1
2
$ svn import /data/www/code file:///opt/svn/repos1 -m 'first init'
$ chown -R apache.apache repos

创建svn版本库

1
$ svnadmin create /opt/svn/testrepos

svnadmin在创建版本库时是root身份,需使用chown改变,保证svn对文件目录有权限

玉伯的一份ppt

在这份Seajs的PPT中,玉伯介绍到了Seajs的实现

1
2
3
4
5
6
7
8
9
/*a.js*/
define(function(require, exports, module){
var b = require('./b');
var c = require('./c');
//other code
});

/*main.js*/
seajs.use(./a);

  • Step1: 解析 ‘./a’
  • Step2.1: 下载a
  • Step2.2: 执行define,保存a的factory
  • Step2.3: 得到依赖b和c
  • Step2.4: 加载b和c
  • Step3: 执行a的factory,得到a的module.exports

Step1: 路径解析

在进行路径解析的时候require('jquery'),首先判断在seajs.config是否定义了该alias,

如果存在替换.(parseAlias)

这之后在根据base,将id值解析为uri.(id2uri)

在接下来进行(parseMap), 即对seajs.config中的map进行解析。

最终得到完整的路径!

Step2: 模块加载_

  • 将上一步得到的路径通过 insert script 、xhr、web workder…等方式插入

More See PPT

首先查看之前编译安装nginx的配置

1
$ nginx -V

会列出配置的参数:

1
configure arguments: --prefix=/usr/local/webserver/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module --with-http_flv_module

重新编译增加模块

这个过程不会替换现有的nginx的东西,既可以在不停止服务的前提下进行替换

首先找到原来安装nginx的目录(如果已经删除,则重新现在nginx源程序)

进入该目录,然后执行:

1
2
3
4
5
$ ./configure --prefix=/usr/local/webserver/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module --with-http_flv_module --add-module path/module/

$ make

$ make install

保险做法:

不执行make install, 将执行make之后objs目录下的nginx替换现有的。(不要忘记对之前的进行备份)

1
2
3
4
5
6
7
8
9
10
11
$ ./configure --prefix=/usr/local/webserver/nginx --user=nginx --group=nginx --with-http_stub_status_module --with-http_ssl_module --with-http_flv_module --add-module path/module/

$ make

$ service nginx stop

$ cp /etc/nginx/sbin/nginx /etc/nginx/sbin/nginx.bak

$ cp objs/nginx /etc/nginx/sbin/

$ service nginx start

测试是否安装成功

create database with utf-8

1
CREATE DATABASE `database_name` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

当没有权限访问服务器的mysql的解决办法:

1
GRANT ALL PRIVILEGES ON *.* TO root@'%' IDENTIFIED BY 'root-password' WITH GRANT OPTION;

mysql乱码:

1
$ vi /etc/my.cnf

添加:
[client]
default-character-set=utf8
重启mysql

1
$ service mysqld restart

mysql数据库数据导入与导出

1、导出数据库为dbname的表结构(其中用戶名为root,密码为dbpasswd,生成的脚本名为db.sql)

1
$ mysqldump -uroot -pdbpasswd -d dbname >db.sql;

2、导出数据库为dbname某张表(test)结构

1
$ mysqldump -uroot -pdbpasswd -d dbname test>db.sql;

3、导出数据库为dbname所有表结构及表数据(不加-d)

1
$ mysqldump -uroot -pdbpasswd  dbname >db.sql;

4、导出数据库为dbname某张表(test)结构及表数据(不加-d)

1
$ mysqldump -uroot -pdbpasswd dbname test>db.sql;

5、忽略某张或者多张表导出

1
$ mysqldump -uroot -pdbpasswd dbname --ignore-table=dbname.table1 --ignore-table=dbname.table2 > db.sql

修改表名,列名

  • 添加列:alter table 表名 add column 列名 varchar(30);
  • 删除列:alter table 表名 drop column 列名;
  • 修改列名:alter table 表名 change 旧列名 新列名;

问题

现在需要支持这种方式:

1
light.ifenqi.com => www.ifenqi.com/site/user?name=light

解决步骤

设置vhosts如下:

1
2
3
4
5
<VirtualHost *:80>    
DocumentRoot "D:\project\ifenqi\frontend\web"
ServerName www.ifenqi.com
ServerAlias *.ifenqi.com
</VirtualHost>

注意:这项要配置在所有的地下,否则访问manager.ifenqi.com的话也会被解析到上面的服务器目录

接下来就是按照yii的urlManager,来添加规则了,详见runtime-routing

PHP获取当前类名、函数名、方法名

  • CLASS获取当前类名
  • FUNCTION 获取当前函数名
  • METHOD 获取当前方法名

(返回区分大小写)

关于PHP中的函数

  • 函数名是大小写无关的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function Test() {
    echo 'test';
    }

    test();// print test

    class Test
    {
    public function Say()
    {
    echo 'say something';
    }
    }
    $t = new Test;
    $t->say(); //print say something
  • 函数无需在调用之前被定义,但有两个特例

    • 当一个函数是有条件被定义时,其定义必须在调用之前先处理。
    • 函数中的函数

PHP 中的所有函数和类都具有全局作用域,可以定义在一个函数之内而在之外调用,反之亦然。

关于函数中的函数例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
function foo()
{
function bar()
{
echo 'I will exist until foo() is called!';
}
}

/* 先在还不能调用bar(),因为还不存在 */
foo();

/*因为foo()函数的执行使bar()变为已定义函数*/
bar();

接口可以指定某些类必须实现哪些方法,但不需要定义这些方法的具体内容, 所以定义的所有方法都是空的

需要注意的点

要实现一个接口,使用implements操作符。类中必须实现接口中定义的所有方法,类可以实现多个接口,用逗号来分割多个接口名称。

  • 接口中所有的方法都必须是公有的,这是接口的特性

  • 实现多个接口时,接口中的方法不能有重名

  • 接口也可以通过extends操作符实现继承

  • 类要实现接口,必须使用和接口中所定义的方法完全一致的方式。

  • 接口中也可以定义常量,不能被子类或子接口所覆盖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <?php
    //声明一个'iTemplate'接口
    interface iTemplate
    {
    public function setVariable ($name, $var);
    public function getHtml ($template);
    }

    //实现接口
    class Template implement iTemplate
    {
    private $vars = array();

    public function setVariable($name, $var)
    {
    $this->vars[$name] = $var;
    }

    public function getHtml($template)
    {
    foreach($this->vars as $name => $value)
    {
    $template = str_repleace('{' . $name . '}', $value, $template);
    }
    return $template;
    }
    }