【问题标题】:Activerecord-association: create new object (find class)Activerecord-association:创建新对象(查找类)
【发布时间】:2012-02-14 16:25:50
【问题描述】:

我有一个带有关系的模型,我想实例化一个关系类型的新对象。

示例:一个人有一家公司,我有一个人-对象:现在我 想要创建一个公司对象。

companyobject 的类是在关系中定义的,所以我认为我不需要“知道”那个类,但我应该能够要求 person-object 为我提供一个新的类型实例公司?但我不知道怎么做。

这是 - 我认为 - 与 New model object through an association 相同的问题,但我使用的是 PHPActiveRecord,而不是 ruby​​ 问题。


这背后的原因:我有一个抽象超类person,两个孩子与一种公司对象有自己的关系。我需要能够在抽象人中实例化正确的类。

一种解决方法是直接从static $has_one 数组中获取它:

$class   = $this::$has_one[1]['class_name'];
$company = new $class;

当然可以通过在数组中搜索关联名称来消除硬编码的数字,但这仍然很丑。


如果有人知道这是如何在 Ruby 中实现的,以及 phpactiverecord 实现有何不同,我可能会从那里得到一些想法?


一些测试表明,虽然“在数组中搜索我的类名”看起来有点奇怪,但它对性能没有任何影响,并且在使用中它足够实用。

【问题讨论】:

  • @charles: phpactiverecord 是一个特定的库,所以这个标签实际上是有用的。如果您认为这太过分了,请删除 activerecordtag 而不是描述我使用什么库的标签
  • 不确定这是否有帮助,但我正在阅读有关反射类的信息。 php.net/manual/en/book.reflection.php。它根据各种可能性检查类和方法。这可能会对您有所帮助。
  • 遗憾的是,我认为它不会有帮助:在撰写本文时,该对象尚未生成,这是 lib 为您所做的,仍然感谢 :)

标签: php phpactiverecord


【解决方案1】:

您也可以在关系类中使用build_association()
使用它的最简单方法是通过模型的 __call,即如果您的关系类似于 $person->company,那么您可以使用
$company = $person->build_company()

实例化公司

请注意,这也不会在您的对象之间建立“连接”(不会设置$person->company)。
或者,您可以使用create_company() 而不是build_company(),这将保存新记录并将其链接到$person

【讨论】:

  • 等等?!这有点像我要找的东西?!让我测试:)
  • 是的,我知道 :) 不客气。不幸的是,文档中没有涵盖这些类型的调用
  • 显然这只适用于 has_one?知道has_many应该有什么类似的功能吗?
  • 它也应该与 has_many 一起使用,因为 build_association() 和 create_association() 是基本 AbstractRelationship 类的函数(实际上在 HasMany 中重新实现,请参阅 phpactiverecord.org/docs/ActiveRecord/HasMany)。我还没有测试过
【解决方案2】:

在 PHPActiveRecord 中,您可以访问关系数组。关系应该有一个名称,您需要知道您想要的关系/协会的名称。它不需要是类名,但你所关联的模型的类名应该在关系中明确指出。只是一个基本示例,没有错误检查或坚韧不拔的关系数据库细节,如链接表或外键列名:

class Person extends ActiveRecord\Model {
    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();

【讨论】:

  • 你知道我说的是“phpactiverecord”,一个库(在问题中链接),而不是一个完整的家庭构建框架?如果您从头开始构建,这可能是一个有效的提示,但这并不是问题的真正含义......对不起......
  • @Nanne 我调整了答案以完全使用 PHPActiveRecord 语法。希望这有助于使我的示例更清楚地解决您的问题。
  • 我不太确定你想在这里做什么?在我看来,这一行:self::$belongs_to[$relationshipName]['class_name']; 返回错误,因为公司不是键,而是值。此外,关联的语法如下:static $belongs_to = array(array('company','class_name' => 'class_name')); 您可以硬编码公司的索引(数字)(我在问题中提供了类似的 hack:$class = $this::$belongs_to[0]['class_name'];。)或者您可以查找名称,就像我的回答一样?两者都不是很好,所以我正在寻找第三种选择。
  • @Nanne 抱歉,我错过了关系数组不使用关系名称,因为它是我通常在其他 ORM 中看到的键/索引......会更有意义并提供更快的访问。请参阅上面的更新,为您提供答案。
  • @Nanne,算了,我从上面的阅读中看到你做出了和我刚才一样的选择。是的,他们应该将它添加到 PHPActiveRecord。他们还应该将关系名称移动为数组中的键。
【解决方案3】:

我目前正在使用以下解决方案。这是一个实际的解决方案,而不是 我在问题中提到的$has_one[1] hack。如果有一个 phpactiverecord中的方法我会觉得很傻暴露 自我。但是,请证明我很傻,所以我不需要使用它 解决方案:D

我很傻。以下功能由 create_associationname 调用实现,由@Bogdan_D 回答


添加了两个功能。您可能应该将它们添加到 \ActiveRecord\Model 类中。在我的例子中,我们的类和包含额外功能的模型之间有一个类,所以我把它放在那里。

这是两个功能:

  • public function findClassByAssociation($associationName)
    • 使用您要查找的关联名称进行调用。
    • 检查关联的三个静态变量(has_manybelongs_tohas_one
    • 如果找到关联,则调用findClassFromArray
    • 来自个人/公司示例:$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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多