has_many通过使用自定义表和字段名称

时间:2012-12-27 21:44:23

标签: php phpactiverecord

我正在使用php.activerecord,我正在尝试将表格链接在一起。我没有使用他们的结构,但php.activerecord假设我,所以它并不总是有用。我正在尝试在已经制作的应用程序上使用它,因此我无法更改数据库。

我从上一个问题中了解到 - Model association with custom table and key names - 我需要尽可能明确地使用primary_keyforeign_key字段。

我现在使用has_many through遇到问题。我一直在NULL,我不明白为什么。

所以,这是一个场景:我有3个表,contactscontactPrefspreferences。这些表格如下

contacts
--------
contactID
name
status

contactPrefs
------------
contactID
prefID
prefValue

preferences
-----------
prefID
name
description

每个contact都有多个contactPrefs。每个contactPrefs都有一个preferences。我尝试使用has_many来实现这一点,但事实并非如此。这是我的模特:

Contacts.php

<?php
class Contact extends ActiveRecord\Model {
    static $primary_key = 'contactID';

    static $has_many = array(
        array(
            'prefs',
            'foreign_key' => 'contactid',
            'primary_key' => 'contactid',
            'class_name' => 'ContactPref'
        ),
        array(
            'preferences',
            'foreign_key' => 'prefid',
            'primary_key' => 'prefid',
            'through' => 'prefs',
            'class_name' => 'Preference'
        )
    );
}

ContactPref.php

<?php
class ContactPref extends ActiveRecord\Model {
    static $table_name = 'contactPrefs';

    static $belongs_to = array(
        array(
            'contact',
            'foreign_key' => 'contactid',
            'primary_key' => 'contactid'
        ),
        array(
            'preference',
            'foreign_key' => 'prefid',
            'primary_key' => 'prefid'
        )
    );
}

Preference.php

<?php
class Preference extends ActiveRecord\Model {
    static $primary_key = 'prefID';

    static $has_many = array(
        array(
            'prefs',
            'foreign_key' => 'prefid',
            'primary_key' => 'prefid',
            'class_name' => 'ContactPref'
        )
    );
}

根据the docs,我现在应该能够做到以下几点:

<?php
var_dump(Contact::find(1234)->preference);

我做不到。我得到NULL。奇怪的是,我可以这样做:

<?php
var_dump(Contact::find(1234)->prefs[0]->preference);

这是正常的。但是,我不应该能够通过preference对象直接访问contact对象吗?我是否误解了文档(在我看来,它们不是最好的)?我做错了吗?

3 个答案:

答案 0 :(得分:1)

首先,您正在阅读带有小缺陷的文档。在文档中显示:

$order = Order::first();
# direct access to users
print_r($order->users); # will print an array of User object

您已通过Contact::find(1234)->prefs进行的操作。让我把它煮一点

$contact = Contact::find(1234);
# direct access to prefs
print_r($contact->prefs); # will print an array of ContactPref object

其次,你真正想要的是未定义Contact::find(1234)->preference实际上应该做什么?返回第一个 ContactPref 的首选项?返回首选项对象的数组?

我想提供两者:

<?php
class Contact extends ActiveRecord\Model {
    static $primary_key = 'contactID';

    static $has_many = array(
        array(
            'prefs',
            'foreign_key' => 'contactid',
            'primary_key' => 'contactid',
            'class_name' => 'ContactPref'
        ),
        array(
            'preferences',
            'foreign_key' => 'prefid',
            'primary_key' => 'prefid',
            'through' => 'prefs',
            'class_name' => 'Preference'
        )
    );

    public function get_preference() {
        return isset($this->prefs[0])
            ? $this->prefs[0]->preference
            : null
        ;
    }
    public function get_preferences() {
        $preference=array();
        foreach($this->prefs as $pref) {
            $preference[]=$pref;
        }
        return $preference;
    }
}

让我解释一下我所做的一切。 ActiveRecord \ Model 类有一个 __ get($ name) 函数,用于查找另一个名为 get _ $ name ,其中 $ name 首选项(对于第一个结果)和首选项(适用于整个系列)。这意味着您可以Contact::find(1234)->preference执行与Contact::find(1234)->prefs[0]->preference相同(但由于检查更安全)和Contact::find(1234)->preferences以获取整个首选项集合。

这可以通过多种方式改进或优化,所以请不要按原样使用,但请尝试根据您的具体情况进行调整。 例如,您可以使用首选项的id作为数组中的索引,或者不强制加载来自 ContactPrefs 的更多数据而不是您要使用的数据,并尝试更复杂的查询获取您特别需要的首选项对象。

如果我通过通过在关系定义中工作找到更好的实现,我将返回。但是看到Unit Tests的活跃记录,我持怀疑态度。

答案 1 :(得分:0)

有几件事情看起来很奇怪,所以要找到“这会解决它”并不容易,但至少这是一个问题:

在phpactiverecord中,字段名应始终为小写。 SQL无论如何都不介意(不是表名是区分大小写的,而是列名不是)。所以说:

static $primary_key = 'contactID';

static $primary_key = 'contactid';

连接// find命令可以在SQL中使用,在这种情况下,你的key-string是如何'cased'并不重要,所以有些东西可以工作。但是,如果连接通过phpmyadmin的内部工作,它将失败。请查看此contactID以及prefID

同样,这仅适用于COLUMN名称,因此不要将类名或表名更改为小写。

(额外的一点:phpmyadmin组合主键有问题。所以虽然它可能很难看,你可以在你的contactprefs表中添加一个额外的行(如果你还没有它),称为{{1} ,使该表实际上有一些工作。它不会给你带来太多麻烦,它会帮助activerecord库很多)

答案 2 :(得分:0)

尝试以下方法:

<?php 
var_dump(Contact::find(1234)->preferences);

文档说明有一个has_many关系,它应该用复数(http://www.phpactiverecord.org/projects/main/wiki/Associations#has_many_through)引用。 Contact :: find(1234)返回一个Contact对象,该对象具有多个contactPref及其每个Preference。此外,在联系人模型中,您将has_many指定为首选项

static $has_many = array(
    array(
        'prefs',
        'foreign_key' => 'contactid',
        'primary_key' => 'contactid',
        'class_name' => 'ContactPref'
    ),
    array(
        'preferences',
        'foreign_key' => 'prefid',
        'primary_key' => 'prefid',
        'through' => 'prefs',
        'class_name' => 'Preference'
    )
);

通过修改编辑:

尝试以下联系模式

<?php
class Contact extends ActiveRecord\Model {
static $primary_key = 'contactID';

static $has_many = array(
    array(
        'prefs',
        'foreign_key' => 'contactid',
        'class_name' => 'ContactPref'
    ),
    array('preferences', 
          'through' => 'prefs', 
          'class_name' => 'Preference',
          'primary_key' => 'prefID')
);
}