我有一个带有关系的模型,我想实例化一个关系类型的新对象。
示例:一个人有一家公司,而我有一个人对象:现在我想要创建公司对象。
companyobject的类是在关系中定义的,所以我认为我不需要"知道"那个类,但我应该能够要求person对象为我提供类型company的新实例?但我不知道怎么做。
我认为,这与通过关联的New模型对象的问题相同,但我使用的是PHPActiveRecord,而不是ruby。
背后的原因:我有一个抽象的超类
person
,两个孩子与一种类型的公司对象有自己的关系。我需要能够在抽象人中实例化正确的类。
一种解决方法是直接从static $has_one
阵列获取:
$class = $this::$has_one[1]['class_name'];
$company = new $class;
当然,可以通过在数组中搜索关联名称来消除硬编码的数字,但这仍然很难看。
如果有人知道这是如何在Ruby中实现的,以及phpactiverecord的实现有何不同,我可能会从中得到一些想法?
一些测试表明,尽管"在数组中搜索我的类名"看起来有点奇怪,但它对性能没有任何影响,而且在使用中它足够实用。
您也可以在关系类中使用build_association()
使用它的最简单方法是通过Model的__call,即如果您的关系类似于$person->company
,则可以使用$company = $person->build_company()
实例化公司请注意,这不会在对象之间建立"连接"(不会设置$person->company
)
或者,您可以使用create_company()
而不是build_company()
,它将保存新记录并将其链接到$person
在PHPActiveRecord中,您可以访问关系数组。关系应该有一个名字,你需要知道你想要的关系/协会的名字。它不需要是类名,但与之相关的模型的类名应该在关系中明确指示。这只是一个没有错误检查或粗糙关系的基本示例数据库详细信息,如链接表或外键列名:
class Person extends ActiveRecordModel {
static $belongs_to = array(
array('company',
'class_name' => 'SomeCompanyClass')
);
//general function get a classname from a relationship
public static function getClassNameFromRelationship($relationshipName)
foreach(self::$belongs_to as $relationship){
//the first element in all relationships is it's name
if($relationship[0] == $relationshipName){
$className = null;
if(isset($relationship['class_name'])){
$className = $relationship['class_name'];
}else{
// if no classname specified explicitly,
// assume the clasename is the relationship name
// with first letter capitalized
$className = ucfirst($relationship);
}
return $className
}
}
return null;
}
}
使用此功能,如果您有一个个人对象,并且想要一个由"公司"关系定义的对象,请使用:
$className = $person::getClassNameFromRelationship('company');
$company = new $className();
我目前正在使用以下解决方案。相反,这是一个实际的解决方案我在问题中提到的$has_one[1]
黑客。如果有phpactiverecord中的方法我会觉得很傻msyelf。但请证明我很傻,这样我就不需要用这个了解决方案:D我很傻。以下功能由create_associationname调用实现,由@Bogdan_D 应答
增加了两个功能。您可能应该将它们添加到
ActiveRecordModel
类中。在我的例子中,在我们的类和那个模型之间有一个类,它包含这样的额外功能,所以我把它放在那里。
这是两个功能:
public function findClassByAssociation($associationName)
- 使用您要查找的关联的名称调用
- 检查关联的三个静态变量(
has_many
、belongs_to
和has_one
) - 如果找到关联,则调用CCD_ 15
- 来自个人/公司示例:
$person->findClassByAssociation('company');
private function findClassFromArray($associationName,$associationArray)
- 只是一个试图匹配名称的辅助函数
来源:
/**
* Find the classname of an explicitly defined
* association (has_one, has_many, belongs_to).
* Unsure if this works for standard associations
* without specific mention of the class_name, but I suppose it doesn't!
* @todo Check if works without an explicitly set 'class_name', if not: is this even possible (namespacing?)
* @todo Support for 'through' associations.
* @param String $associationName the association you want to find the class for
* @return mixed String|false if an association is found, return the class name (with namespace!), else return false
* @see findClassFromArray
*/
public function findClassByAssociation($associationName){
//$class = $this::$has_one[1]['class_name'];
$that = get_called_class();
if(isset($that::$has_many)){
$cl = $this->findClassFromArray($associationName,$that::$has_many);
if($cl){return $cl;}
}
if(isset($that::$belongs_to)){
$cl = $this->findClassFromArray($associationName,$that::$belongs_to);
if($cl){return $cl;}
}
if(isset($that::$has_one)){
$cl = $this->findClassFromArray($associationName,$that::$has_one);
if($cl){return $cl;}
}
return false;
}
/**
* Find a class in a php-activerecord "association-array". It probably should have a specifically defined class name!
* @todo check if works without explicitly set 'class_name', and if not find it like standard
* @param String $associationName
* @param Array[] $associationArray phpactiverecord array with associations (like has_many)
* @return mixed String|false if an association is found, return the class name, else return false
* @see findClassFromArray
*/
private function findClassFromArray($associationName,$associationArray){
if(is_array($associationArray)){
foreach($associationArray as $association){
if($association['0'] === $associationName){
return $association['class_name'];
}
}
}
return false;
}