Laravel 4中的通用访问器和修改器

12

我知道可以为单个字段定义访问器和修改器,例如:

public function setSomeAttribute($value) {
    // set the attribute
}
public function getSomeAttribute() {
    // return the attribute}
}

但是,有没有可能定义一个回调方法来处理所有属性的获取和设置?

原因在于,我想即时将任何空值转换为 null 值,以保持数据库的清洁,并允许可空字段为空而不是空字符串(如果有更好的方法,请告诉我!)

我正在寻找像这样的东西:

public function setAttribute($property,$value) {
    $this->$property = empty($value) ? null : $value;
}

更新:

感谢Chris Goosey,我找到了适合我的解决方案。我扩展了Eloquent模型方法setAttribute,并在值为空时将其设置为列默认值。这通常是我的数据库中的null、零或空字符串,所以对我有效!

public function setAttribute($key, $value)
{
    // Convert empty values to their default values (e.g. null, zero)
    if(empty($value) && $this->getSchema()->hasColumn($key)) {
        $value = $this->getSchema()->getColumn($key)->getDefault();
    }
    parent::setAttribute($key,$value);
}
1个回答

13

最好的方法可能是扩展Eloquent类,覆盖setAttribute和getAttribute方法。

为了使所有模型都继承这些重写的方法,您需要创建一个扩展Eloquent的类,例如:

<?php 

class BaseModel extends eloquent {

    public function setAttribute($property,$value) {
        $this->$property = empty($value) ? null : $value;
    }

    public function getAttribute($key) {
        // Do Stuff
    }
}

然后所有的模型都应该从这个新类继承,例如:

<?php

class User extends BaseModel {
    protected $table = 'users';
}

值得一提的是,你的新方法应该具备旧方法的全部功能以及你的新功能。这就是getAttribute()函数的样子(位于Illuminate\Database\Eloquent第2212行):

/**
 * Get an attribute from the model.
 *
 * @param  string  $key
 * @return mixed
 */
public function getAttribute($key)
{
    $inAttributes = array_key_exists($key, $this->attributes);

    // If the key references an attribute, we can just go ahead and return the
    // plain attribute value from the model. This allows every attribute to
    // be dynamically accessed through the _get method without accessors.
    if ($inAttributes || $this->hasGetMutator($key))
    {
        return $this->getAttributeValue($key);
    }

    // If the key already exists in the relationships array, it just means the
    // relationship has already been loaded, so we'll just return it out of
    // here because there is no need to query within the relations twice.
    if (array_key_exists($key, $this->relations))
    {
        return $this->relations[$key];
    }

    // If the "attribute" exists as a method on the model, we will just assume
    // it is a relationship and will load and return results from the query
    // and hydrate the relationship's value on the "relationships" array.
    $camelKey = camel_case($key);

    if (method_exists($this, $camelKey))
    {
        return $this->getRelationshipFromMethod($key, $camelKey);
    }
}

在同一文件中,setAttribute 看起来像这样(第 2338 行):

/**
 * Set a given attribute on the model.
 *
 * @param  string  $key
 * @param  mixed   $value
 * @return void
 */
public function setAttribute($key, $value)
{
    // First we will check for the presence of a mutator for the set operation
    // which simply lets the developers tweak the attribute as it is set on
    // the model, such as "json_encoding" an listing of data for storage.
    if ($this->hasSetMutator($key))
    {
        $method = 'set'.studly_case($key).'Attribute';

        return $this->{$method}($value);
    }

    // If an attribute is listed as a "date", we'll convert it from a DateTime
    // instance into a form proper for storage on the database tables using
    // the connection grammar's date format. We will auto set the values.
    elseif (in_array($key, $this->getDates()))
    {
        if ($value)
        {
            $value = $this->fromDateTime($value);
        }
    }

    $this->attributes[$key] = $value;
}

希望这可以帮到您!


太好了!这正是我在寻找的,谢谢!我已经使用我的最终代码更新了我的问题。 - tprsn
看起来这将覆盖个别模型中更具体的setAttributes。有没有什么办法可以避免这种情况? - Staysee
如果个别模型具有setAttribute()或getAttribute()函数,则它们将覆盖BaseModel中的任何此类函数。您为什么认为BaseModel正在覆盖个别模型? - Chris Goosey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接