十一月
10
2016

FOSUserBundle 中四种状态标识的含义说明

Security component in Symfony2 defines 4 flags related to the user. These are: enabled, locked, expired, credentialsExpired. Once the semantics of the two last of them seems to be easy to understand (the expired flag simply means that a user has been archived and the credentialsExpired flag means that a user needs to change his password), there are some concerns about the meaning of enabled and locked flags. As Fabien Potencier, the founder of Symfony framework, claims, “this part of Symfony is a direct port of Spring Security, which was named Ageci some years ago”. There is old forum post about the original meaning of enabled and locked flags in Ageci. The following is being described: Disabled indicates an account has been administratively or automatically disabled for some reason. Usually some action is required to release it. Locked indicates an account has been automatically suspended due to invalid login attempts. Usually the passage of time or (less often) requesting manual unlocking is required to release it.
七月
14
2016

使用解析缓存器缓存表达式

表达式语言(ExpressionLanguage)组件已经提供了一个 compile() 方法来允许缓存原生 PHP。事实上,该组件也可以缓存解析过的表达式,因此,重复的表达式可以更快地被编译和执行。 工作流程 在提供返回值之前,evaluate() 和 compile() 两个方法需要额外做一些工作。对于 evaluate() 方法,这些开销会更大。 两个方法均需要标记和解析表达式。这些工作都可以通过 parse() 方法来完成。它将返回一个 ParsedExpression 对象。目前,compile() 方法只是返回一个该对象转化而成的字符串。evaluate() 方法则还需要循环地动态执行 “节点(nodes)”(保存在 ParsedExpression 中的表达式片段)。 在保存阶段,表达式语言(ExpressionLanguage)将缓存解析后表达式(ParsedExpression),因此重复的表达式将跳过标记(tokenize)和解析(parse)步骤。缓存功能将被解析缓存器接口(ParserCacheInterface)的实例完成(默认情况下,会使用数组解析缓存器(ArrayParserCache))。你可以通过创建自定义的解析缓存器(ParserCache)然后注入到对象的构造方法中来实现缓存功能。 use Symfony\Component\ExpressionLanguage\ExpressionLanguage; use Acme\ExpressionLanguage\ParserCache\MyDatabaseParserCache; $cache = new MyDatabaseParserCache(...); $language = new ExpressionLanguage($cache); DoctrineBridge 提供了一个使用 doctrine cache library 的解析缓存器的实现,该实现为所有分类的缓存策略提供了缓存功能,例如:Apc,Filesystem 和 Memcached。 使用解析和序列化过后的表达式 evaluate() 和 compile() 方法均可以操作 ParsedExpression 和 SerializedParsedExpression: // ... // parse() 方法返回 ParsedExpression $expression = $language->parse('1 + 4', array()); var_dump($language->evaluate($expression)); // 输出 5 use Symfony\Component\ExpressionLanguage\SerializedParsedExpression; // ... $expression = new SerializedParsedExpression( '1 + 4', serialize($language->parse('1 + 4', array())->getNodes()) ); var_dump($language->evaluate($expression)); // 输出 5 原文地址:Caching Expressions Using Parser Caches
七月
13
2016

扩展表达式语言

表达式语言可以通过添加自定义函数进行扩展。例如,在 Symfony 框架中,Security 实现了一个自定义函数用于检查用户角色。 如果想要了解如何在表达式中使用函数,可参考 使用函数 (英文) 注册函数 函数会在每一个特定的 表达式语言 实例上进行注册。这意味着实例中这些被注册的函数可以被实例中的任意表达式执行。 要注册一个函数,需要使用 register() 方法。该方法有三个参数: name - 函数在表达式中的名称 compiler - 编译表达式时要使用的函数 evaluator - 执行表达式时要使用的函数 use Symfony\Component\ExpressionLanguage\ExpressionLanguage; $language = new ExpressionLanguage(); $languate->register('lowercase', function($str) { return sprintf('(is_string(%1$s) ? strtolower(%1$s) : $1$s)', $str); }, function ($arguments, $str) { if (!is_string($str)) { return $str; } return strtolower($str); }); var_dump($language->evaluate('lowercase("HELLO")')); 以上程序会输出 hello。compiler 和 evaluator 两个编译器都将 arguments 变量作为首个参数,该参数的性质等效于 evaluate() 或 comple() 方法的第二个参数(例如:执行时传递的 values,编译时传递的 names)。 使用表达式供应器 当项目中使用 ExpressionLanguage 类时,你经常会需要添加自定义函数。因此,你可以通过实现 ExpressionFunctionProviderInterface 接口创建一个新的表达式供应器。 该接口必须实现一个方法:getFunctions(),该方法需要返回一个值为需要注册的表达式函数(ExpressionFunction 类的实例)数组。 use Symfony\Component\ExpressionLanguage\ExpressionFunction; use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; class StringExpressionLanuageProvider implements ExpressionFunctionProviderInterface { public function getFunctions() { return array( new ExpressionFunction('lowercase', function($str) { return sprintf('(is_string(%1$s) ? strtolower(%1$s) : %1$s)', $str); }, function($arguments, $str) { if (!is_string($str)) { return $str; } return strtolower($str); } ); } } 你可以使用 registerProvider() 方法或者通过 ExpressionLanguage 类的构造方法的第二个参数来注册供给器: use Symfony\Component\ExpressionLanguage\ExpressionLanguage; // 通过构造器进行注册 $language = new ExpressionLanguage(null, array( new StringExpressionLanguageProvider(), // ... )); // 通过 registerProvider() 方法注册 $language->registerProvider(new StringExpressionLanguageProvider()); 推荐在项目中的创建自定义的 ExpressionLanguage 类。目前你可以通过重写构造器来添加扩展功能: use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage; use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface; class ExpressionLanguage extends BaseExpressionLanguage { public function __construct(ParserCacheInterface $parser = null, array $providers = array()) { // 预加载默认的供给器以便于用户进行重载 array_unshift($provider, new StringExpressionLanguageProvider()); parent::__construct($parser, $providers); } } 原文地址:Extending the ExpressionLanguage
七月
08
2016

表达式语法

表达式语言组件使用了一种特殊的基于 `Twig` 的表达式语法。在这一章中,你可以了解到所有支持的语法。资料原文已经在PHP博客文尾附带,翻译不当止住请谅解。

阅读全文>>

七月
07
2016

表达式语言(ExpressionLanguage)组件

表达式语言(ExpressionLanguage)组件是 Symfony 组件之一,该组件对表达式语言进行了功能支持。表达式语言(ExpressionLanguage)提供了一个用于编译和执行表达式的引擎。此篇文章是英文原文的翻译版本,原文地址已经在 PHP 博客的文尾附带。由于能力不足,翻译不准之处还望见谅!

阅读全文>>

六月
24
2016

symfony ParameterBag::resolveValue() 方法的用途

说明 symfony 中参数包 ParameterBag 的 resolveValue() 方法是个很常用的方法。 当然,我这里所谓的常用是指 symfony 系统内部,对于那些不在意 symfony 内部代码的朋友们,此处可以忽略了。 该方法很常用,Hy369 本身也觉得比较重要且时间一长就容易迷糊,所以特地记录在自己的 PHP 博客中。 方法解释 既然这里提到了 ParameterBag::resolveValue() 方法,那么就无法绕开 ParameterBag::get() 和 ParameterBag::resolveString() 方法了,因为这几个方法是紧密关联的。所以 ParameterBag::get() 和 ParameterBag::resolveString() 功能也会在这里一并记录。 ParameterBag::get($name) 参数: $name 需要获取的参数的名称 函数作用: 通过提供的参数名称,从 ParameterBag::parameters 参数包的参数属性中取得对应的值。 这里要特别提到一个功能,代码片段如下: $alternatives = array(); foreach ($this->parameters as $key => $parameterValue) { $lev = levenshtein($name, $key); if ($lev <= strlen($name) / 3 || false !== strpos($key, $name)) { $alternatives[] = $key; } } 这段代码在对应的参数名称不存在时,会遍历所有已经存在的参数,通过 levenshtein() 函数进行参数比较,从而筛选出比较相近的参数名称,然后在接下来抛出的异常中给出可能值的提示。不得不说,这是一个让我惊叹的代码,哈哈。 ParameterBag::resolveValue($value, array $resolving = array()) 参数: $value 需要进行解析的值,数组和字符串值会进行解析,其它值直接返回传递的值 $resolving 为已经解析过的字符串的集合,该参数用于避免死循环解析 函数作用: 数组类型的值则对该数组进行遍历,然后对数组的键与值均进行 ParameterBag::resolveValue() 递归解析 非数组非字符串类型的值,直接返回本身 字符串值调用 ParameterBag::resolveString() 方法进行字符串解析 ParameterBag::resolveString($value, array $resolving = array()) 参数: $value 是需要进行解析的字符串 $resolving 为已经解析过的字符串的集合,该参数用于避免死循环解析 函数作用: 匹配符合正则 /^%([^%\s]+)%$/ 的字符串,也就是匹配类似 %name% 格式的字符串,如果匹配成功: 如果匹配到的 name 在 $resolving 参数中存在对应的键,则说明出现了死循环解析,此时抛出异常 反之,说明可正常进行解析,在将 name 以 array(name => true) 的形式录入 $resolving 参数中后,通过 ParameterBag::get() 方法取得对应的值。 接下来有个小的分支,若是 ParameterBag::resolved 属性为真,则不对取得的值进行再解析;若属性为假,则继续对取得的值进行再解析 然后将能够匹配正则 /%%|%([^%\s]+)%/ 的字符串,类似 %% 或 %name% 的字符串进行处理后,返回处理后的结果 如果匹配到的字符串为 %%,表明这是一个 % 符号的转义形式,此时直接返回 %% 检测是否死循环解析,即检查 $resolving 参数中是否已经存在对应的键,死循环时抛出异常 获得 name 为名称的参数的值,若参数的值不为字符串或数字,则抛出异常,因为 symfony 本身要求参数必须是字符串或数字 然后判断 ParameterBag::resolved 属性的真假,决定是否进行再解析,最后返回解析后的值
六月
23
2016

symfony 字符串驼峰式/下划线式互转方法

说明 在阅读 symfony 源码的过程中,发现了字符串驼峰式/下划线式互转方法。 虽然这类方法完全可以自己来写,但是每次遇到都要写一遍的话,从时间成本上来看,简直是浪费了。既然要使用 symfony 框架,那么为何要抛开其本身就提供了的功能,自己去另外搞一套呢。所以 Hy369 觉得还是有必要在自己的专用PHP博客中记录一下,以备将来可以直接拿来使用。 驼峰式字符串转换 symfony 中提供的驼峰式转换方法是: Container::camelize($id) 该方法会对以下字符进行转换: 首字母大写 _ 将被去掉,同时其后的字母大写 . 将被转换为 _,同时其后的字母大写 \ 将被转换为 _,同时其后的字母大写 从上面可以看出,这里得出的驼峰式字符串属于首字母大写型,若是需要一个首字母小写型的字符串,执行首字母小写函数 ` lcfirst()· 就可以了。 下划线式字符串转换 symfony 中提供的下划线式转换方法是: Container::underscore($id) 该方法会对以下字符串进行转换: 本身的 _ 被装换为 . 连续大写的字母,最后两个大写字母之间插入 _,然后字母全部小写,例如 IDTt 将转换为 id_tt 小写字母或者数字后面跟着一个大写字母,在大写字母前面插入 _,该大写字母小写,例如 abcTest 将转换为 abc_test 不匹配上述规则的所有大写字母直接转换为小写
五月
23
2016

symfony 的惰性服务(Lazy Services)

Hy369 在自己的 PHP 博客中为你推荐如下内容:在某些时候,你也许需要向系统中注入一个笨重的实例(功能繁多庞大),但是这个实例你又只是偶尔才会在某些地方用到。举个例子,假如你有一个 通信管理器(NewsletterManager) ,你在其中注入了一个 mailer 邮件服务。在这个通信管理器中,只有屈指可数的一两个方法会用到这个 mailer 服务,然而不管你是否需要用到这个 mailer 服务,这个 mailer 服务总会被实例化,用于构建你的通信管理器。这个时候,为通信管理器配置一个惰性服务,就可以解决这个让人尴尬的问题了。通过惰性服务,系统会将 mailer 服务的一个代理(proxy) 注入到通信管理器中,这个代理将扮演 mailer 服务的角色,但是它不会被实例化。直到通信管理器真正需要用到 mailer 服务的时候,这个代理才会帮助实例化这个 mailer 服务。

阅读全文>>

五月
12
2016

秒表组件(Stopwatch Component)

组件介绍 秒表组件用于提供计时器功能,用于跟踪某个部分的代码执行用时。秒表组件由外到内,支持秒表节点、秒表事件、秒表周期。这意味着,对一个代码整体,可以对代码分节、分事件、每个事件还可以分不同的周期,然后分别计时与汇总。 Stopwatch 实例化以后,自带根节点 __root__。所有新的节点均是该节点的子节点。 代码摘要 类 Symfony\Component\Stopwatch\Stopwatch 类 Symfony\Component\Stopwatch\Section 类 Symfony\Component\Stopwatch\StopwatchEvent 类 Symfony\Component\Stopwatch\StopwatchPeriod
五月
10
2016

类 Symfony\Component\Stopwatch\Stopwatch

类简介 秒表类,统一调度秒表节点、秒表事件、秒表周期 类摘要 Stopwatch { private Section[] $sections private Section[] $activeSection public __construct() public Section getSections() public void openSection($id = null) public void stopSection($id) public StopwatchEvent[] start($name, $category = null) public boolean isStarted($name) public StopwatchEvent stop($name) public StopwatchEvent lap($name) public StopwatchEvent getEvent($name) public StopwatchEvent[] getSectionEvents($id) } 属性 sections 秒表节点实例集合 activeSection 已激活的秒表节点的实例集合 方法 Stopwatch::__construct 秒表的构造方法 Stopwatch::getSections 获取当前秒表的所有秒表节点 Stopwatch::openSection 打开一个秒表节点 Stopwatch::stopSection 结束最后一个开始的秒表节点 Stopwatch::start 开始已激活最后一个秒表节点的某个秒表事件 Stopwatch::isStarted 判断已激活最后一个秒表节点的某个事件是否开始 Stopwatch::stop 结束已激活最后一个秒表节点的某个秒表事件 Stopwatch::lap 结束已激活最后一个秒表节点的秒表事件,并开始一个新的秒表事件 Stopwatch::getEvent 获取已激活最后一个秒表节点的某个秒表事件 Stopwatch::getSectionEvents 获取某个秒表节点的所有秒表事件