【问题标题】:Laravel - Set Default Value for Relation ModelsLaravel - 为关系模型设置默认值
【发布时间】:2014-12-05 19:41:44
【问题描述】:

我有一个表帐户:

act_id,
act_name,
act_address

我有一个表地址:

add_id,
add_street1,
<other fields you'd expect in an address table>

accounts.act_address 是addresses.add_id 的外键。在 Laravel 中,我有我的 Account 模型:

use LaravelBook\Ardent\Ardent;
use Illuminate\Database\Eloquent\SoftDeletingTrait;

class Account extends Ardent
{
    use SoftDeletingTrait;

    protected $table = 'accounts';

    protected $primaryKey = 'act_id';

    public static $rules = array
    (
        'act_name' => 'required|unique:accounts'
    );

    protected $fillable = array
    (
        'act_name'
    );

    public function address()
    {
        return $this->hasOne('Address', 'add_id', 'act_address');
    }
}

如您所见,我在这里设置了一对一的关系。 (当然,Address 模型也有一个“belongsTo”)。这一切都有效。

问题是,地址外键可以为空,因为帐户不需要地址。因此,如果我在没有帐户的情况下尝试访问 Account->address,则会收到“尝试访问非对象的属性”错误。

如果帐户记录没有设置,我想做的是将 Account->address 设置为新的 Address 对象(所有字段为空)。

我能够做的是在模型中创建第二个方法:

public function getAddress()
{
    return empty($this->address) ? new Address() : $this->address;
}

或者,即时添加:

if (empty($account->address))
    $account->address = new Address();

第一个解决方案非常接近,但我真的很想将访问地址的功能保留为属性而不是方法。

所以,我的问题是:
如果 Account->address 为空/null,我如何让 Account->address 返回 new Address()?

哦,我尝试像这样覆盖 $attributes:

protected $attributes = array
(
    'address' => new Address()
);

但这会引发错误。

【问题讨论】:

    标签: php laravel-4 eloquent


    【解决方案1】:

    使用访问器:

    编辑:因为它是 belongsTo 而不是 hasOne 关系,所以有点棘手 - 你不能将模型与不存在的模型相关联,因为后者没有 id

    public function getAddressAttribute()
    {
        if ( ! array_key_exists('address', $this->relations)) $this->load('address');
    
        $address = ($this->getRelation('address')) ?: $this->getNewAddress();
    
        return $address;
    }
    
    protected function getNewAddress()
    {
        $address = $this->address()->getRelated();
    
        $this->setRelation('address', $address);
    
        return $address;
    }
    

    但是,现在你需要这个:

    $account->address->save();
    $account->address()->associate($account->address);
    

    这不是很方便。您也可以将新实例化的地址保存在getNewAddress 方法中,或者覆盖Account save 方法,以自动进行关联。无论如何,对于这种关系,我不确定这样做是否有意义。对于hasOne,它会很好玩。


    下面是hasOne 关系的样子

    public function getAddressAttribute()
    {
        if ( ! array_key_exists('address', $this->relations)) $this->load('address');
    
        $address = ($this->getRelation('address')) ?: $this->getNewAddress();
    
        return $address;
    }
    
    protected function getNewAddress()
    {
        $address = $this->address()->getRelated();
    
        $this->associateNewAddress($address);
    
        return $address;
    }
    
    protected function associateNewAddress($address)
    {
        $foreignKey = $this->address()->getPlainForeignKey();
    
        $address->{$foreignKey} = $this->getKey();
    
        $this->setRelation('address', $address);
    }
    

    您可以在单个访问器中完成所有这些操作,但这是它“应该”的样子。

    【讨论】:

    • 就返回一个新的地址对象而言,这就是我所需要的,但是当我使用 $account->address()->save(new Address($params)) 创建一个对象时,它不起作用。它同时创建帐户和地址,但 accounts.act_id 确实设置为addresses.add_id。
    • 显示代码和问题所在。它与方法调用$account-&gt;address() 无关,因此它不会干扰其save 方法。顺便说一句,我更改了getNewAddress 以避免显式调用new Address
    • 还有,你确定关系没问题吗? hasOne 表示 Address 表包含与 Account 表主键相关的外键。您的表格很难阅读,但您似乎看错了。
    • 虽然我确实说过这是一对一的关系,但实际上它是设置为多对一的。多个帐户可以指向同一个地址。因此,accounts 表只有 address.add_id 列的外键。我对另外两个表做同样的事情,它工作正常。但是,该外键是必需的,所以我没有遇到我最初提出的问题。我正在更新我的帖子以提供更多信息。
    • 是的,我就是这么想的。所以关系是错误的,你需要Account belongsTo AddressAddress hasMany Account。我稍后会调整此设置的代码。
    猜你喜欢
    • 1970-01-01
    • 2018-05-23
    • 2013-09-15
    • 2019-06-21
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    • 2016-02-20
    相关资源
    最近更新 更多