覆盖 KNP DoctrineBehaviors "under-the-hood"
Override KNP DoctrineBehaviors "under-the-hood"
我正在写一个 SEO 包,主要由两部分组成:
- 一个表单扩展(用于在表单中添加 slug/title/desc 个字段)
- 一个特征 Seoable 包含实体端的那些字段
最重要的是,我想使用 sluggable trait 站在 KNP DoctrineBehaviors 的肩膀上。
我的问题:在我的架构中,Sluggable 特性将被我的 Seoable 特性使用,而不是最终 class。在 DoctrineBehaviors 的内部,我发现特征检查是由 ClassAnalyzer class 完成的,方法是:
/**
* Return TRUE if the given object use the given trait, FALSE if not
* @param ReflectionClass $class
* @param string $traitName
* @param boolean $isRecursive
*/
public function hasTrait(\ReflectionClass $class, $traitName, $isRecursive = false)
{
if (in_array($traitName, $class->getTraitNames())) {
return true;
}
$parentClass = $class->getParentClass();
if ((false === $isRecursive) || (false === $parentClass) || (null === $parentClass)) {
return false;
}
return $this->hasTrait($parentClass, $traitName, $isRecursive);
}
递归部分检查所有祖先class,但不检查特征中包含的特征。
2 个解决方案在我的脑海中:
- 提交关于 KNP DoctrineBehaviors 的拉取请求,并将此递归模式扩展到特征(我最终会这样做)
- 覆盖这部分
DoctrineBehaviors 不是 "regular" 包,这意味着未在 AppKernel 中注册。我如何扩展这部分?
感谢您的回复,
尼古拉斯
多亏了对 this part of cookbook 的更细心的阅读,我检查了 DoctrineBehaviors 配置文件 (vendor/knplabs/doctrine-behaviors/config/orm-services.yml)。
KNP 在这里提供所有参数给侦听器和 类 在 DoctrineBehaviors 包中使用,例如:
parameters:
knp.doctrine_behaviors.reflection.class_analyzer.class: Knp\DoctrineBehaviors\Reflection\ClassAnalyzer
knp.doctrine_behaviors.reflection.is_recursive: true
knp.doctrine_behaviors.translatable_subscriber.class: Knp\DoctrineBehaviors\ORM\Translatable\TranslatableSubscriber
# next...
所以,我只是覆盖了第一个参数,以在参数 config.yml 部分使用我自己的 ClassAnalyser 实例。
作为记录,具有祖先特征检查的递归循环:
/**
* Return TRUE if the given object use the given trait, FALSE if not
* Extends from ClassAnalyzer::hasTrait to check in ancestors traits as well
* @param \ReflectionClass $class
* @param string $traitName
* @param boolean $isRecursive
*/
public function hasTrait(\ReflectionClass $class, $traitName, $isRecursive = false)
{
$classTraits = $class->getTraitNames();
// Trait directly present in final class
if (in_array($traitName, $classTraits)) {
return true;
}
// Check in parents traits
foreach($classTraits as $classTrait) {
$traitObject = new \ReflectionClass($classTrait);
if($this->hasTrait($traitObject, $traitName, $isRecursive)) {
return true;
}
}
// Check in parents classes
$parentClass = $class->getParentClass();
if ((false === $isRecursive) || (false === $parentClass) || (null === $parentClass)) {
return false;
}
return $this->hasTrait($parentClass, $traitName, $isRecursive);
}
我正在写一个 SEO 包,主要由两部分组成:
- 一个表单扩展(用于在表单中添加 slug/title/desc 个字段)
- 一个特征 Seoable 包含实体端的那些字段
最重要的是,我想使用 sluggable trait 站在 KNP DoctrineBehaviors 的肩膀上。
我的问题:在我的架构中,Sluggable 特性将被我的 Seoable 特性使用,而不是最终 class。在 DoctrineBehaviors 的内部,我发现特征检查是由 ClassAnalyzer class 完成的,方法是:
/**
* Return TRUE if the given object use the given trait, FALSE if not
* @param ReflectionClass $class
* @param string $traitName
* @param boolean $isRecursive
*/
public function hasTrait(\ReflectionClass $class, $traitName, $isRecursive = false)
{
if (in_array($traitName, $class->getTraitNames())) {
return true;
}
$parentClass = $class->getParentClass();
if ((false === $isRecursive) || (false === $parentClass) || (null === $parentClass)) {
return false;
}
return $this->hasTrait($parentClass, $traitName, $isRecursive);
}
递归部分检查所有祖先class,但不检查特征中包含的特征。
2 个解决方案在我的脑海中:
- 提交关于 KNP DoctrineBehaviors 的拉取请求,并将此递归模式扩展到特征(我最终会这样做)
- 覆盖这部分
DoctrineBehaviors 不是 "regular" 包,这意味着未在 AppKernel 中注册。我如何扩展这部分?
感谢您的回复,
尼古拉斯
多亏了对 this part of cookbook 的更细心的阅读,我检查了 DoctrineBehaviors 配置文件 (vendor/knplabs/doctrine-behaviors/config/orm-services.yml)。
KNP 在这里提供所有参数给侦听器和 类 在 DoctrineBehaviors 包中使用,例如:
parameters:
knp.doctrine_behaviors.reflection.class_analyzer.class: Knp\DoctrineBehaviors\Reflection\ClassAnalyzer
knp.doctrine_behaviors.reflection.is_recursive: true
knp.doctrine_behaviors.translatable_subscriber.class: Knp\DoctrineBehaviors\ORM\Translatable\TranslatableSubscriber
# next...
所以,我只是覆盖了第一个参数,以在参数 config.yml 部分使用我自己的 ClassAnalyser 实例。 作为记录,具有祖先特征检查的递归循环:
/**
* Return TRUE if the given object use the given trait, FALSE if not
* Extends from ClassAnalyzer::hasTrait to check in ancestors traits as well
* @param \ReflectionClass $class
* @param string $traitName
* @param boolean $isRecursive
*/
public function hasTrait(\ReflectionClass $class, $traitName, $isRecursive = false)
{
$classTraits = $class->getTraitNames();
// Trait directly present in final class
if (in_array($traitName, $classTraits)) {
return true;
}
// Check in parents traits
foreach($classTraits as $classTrait) {
$traitObject = new \ReflectionClass($classTrait);
if($this->hasTrait($traitObject, $traitName, $isRecursive)) {
return true;
}
}
// Check in parents classes
$parentClass = $class->getParentClass();
if ((false === $isRecursive) || (false === $parentClass) || (null === $parentClass)) {
return false;
}
return $this->hasTrait($parentClass, $traitName, $isRecursive);
}