在 Laravel 中扩展访问器和修改器

Extending accessor and mutators in Laravel

我正在尝试在 Laravel 5.5 中开发一个小型应用程序,其中我制作了一个 abstract model,它正在扩展 Laravel eloquent model 类似这样的东西:

<?php

use Illuminate\Database\Eloquent\Model;

class AbstractModel extends Model
{


}

现在为了一般惯例,我为此模型设置了一个数据库连接:

<?php

use Illuminate\Database\Eloquent\Model;

class AbstractModel extends Model
{
    /**
     *  Defining connection for database
     *
     * @var string
     **/
    protected $connection='mysql';

}

我创建了自己的模型来扩展这个 abstract class:

<?php

use Illuminate\Database\Eloquent\SoftDeletes;

class Posts extends AbstractModel
{
    use SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'unique_id', 'title', 'contents'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'id'
    ];

}

通过默认定义它,我们知道它将有一个数据库连接 mysql,类似地,fillable 被定义为批量分配。以类似的方式,我想创建一个 encrypt 变量,它将 encryptdecrypt 来自数据库的数据,因此为此我将 accessormutator 添加到我的encrypt variable 在我的模型中:

<?php

use Illuminate\Database\Eloquent\SoftDeletes;

class Posts extends AbstractModel
{
    use SoftDeletes;

    /**
     * The attributes that will have encryption.
     *
     * @var array
     */
    protected $encryption = ['unique_id', 'title', 'contents'];

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'unique_id', 'title', 'contents'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'id'
    ];

}

并在我的 abstract model:

中重新配置它
<?php

use Illuminate\Database\Eloquent\Model;

class AbstractModel extends Model
{
    /**
     *  Defining connection for database
     *
     * @var string
     **/
    protected $connection='mysql';

    /**
     *  Defining encryption
     *
     * @var array
     **/
    protected $encryption = [];

    public function setAttributes()
    {
        foreach ($this->encryption as $attributes)
        {
            $this->attributes[$attributes] = Crypt::encryptString($this->attributes[$attributes]);
        }
    }

    public function getAttributes()
    {
        foreach ($this->encryption as $attributes)
        {
            $this->attributes[$attributes] = Crypt::decryptString($this->attributes[$attributes]);
        }
    }
}

我认为我的方法是错误的,因为没有对这些属性进行加密或解密,我可以看到发送来创建行的数据存储在数据库中没有任何加密,并且也以相同的方式检索。

此外,我想有一个用例,我正在加密这些字段,并且它们的属性访问器或修改器在它们自己的模型中被调用,例如:

<?php

use Illuminate\Database\Eloquent\SoftDeletes;

class Posts extends AbstractModel
{
    use SoftDeletes;

    /**
     * The attributes that will have encryption.
     *
     * @var array
     */
    protected $encryption = ['unique_id', 'title', 'contents'];

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'unique_id', 'title', 'contents'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'id'
    ];

    public function setTitleAttributes($value)
    {
        return ucfirst($value);
    }

    public function getTitleAttributes($value)
    {
        return ucfirst($value)
    }

}

欢迎任何反馈意见。谢谢。

首先,Eloquent 模型有 setAttribute()getAttribute() 方法,而不是 setAttributes()getAttributes()

其次,对于这种情况。我宁愿使用 Eloquent's event。因为 setAttribute()getAttribute() 方法只会在您动态访问属性时触发,例如:$post->title.

您可以加​​密 saving 事件的属性。并使用 retrieved 事件将其解密。

<?php

namespace App;

use Illuminate\Support\Facades\Crypt;
use Illuminate\Database\Eloquent\Model;

abstract class AbstractModel extends Model
{
    protected $connection = 'mysql';

    protected $encryption = [];

    protected static function boot()
    {
        parent::boot();

        // When being retrieved, decrypt the attributes.
        static::retrieved(function ($instance) {
            foreach ($instance->encryption as $encryptedKey) {
                $instance->attributes[$encryptedKey] = Crypt::decryptString($instance->attributes[$encryptedKey]);
            }
        });

        // When saving (could be create or update) the modal, encrypt the attributes.
        static::saving(function ($instance) {
            foreach ($instance->encryption as $encryptedKey) {
                $instance->attributes[$encryptedKey] = Crypt::encryptString($instance->attributes[$encryptedKey]);
            }
        });

        // Once it's saved, decrypt it back so it's still readble.
        static::saved(function ($instance) {
            foreach ($instance->encryption as $encryptedKey) {
                $instance->attributes[$encryptedKey] = Crypt::decryptString($instance->attributes[$encryptedKey]);
            }
        });
    }
}

当您决定使用这种方法时,不要同时覆盖 setAttribute()getAttribute() 方法。因为它很可能会使 encrypt/decrypt 属性加倍。

此外,它应该是 setTitleAttribute()getTitleAttribute()——单数形式。在 setTitleAttribute() 上你应该改变 title 属性;不返回预期值。我也看不出将 title 大写的目的,因为它无论如何都会被加密。

<?php

namespace App;

class Post extends Model
{
    protected $encryption = ['unique_id', 'title', 'contents'];

    protected $fillable = ['unique_id', 'title', 'contents'];

    // Expected to mutate the title attribute.
    public function setTitleAttribute($value)
    {
        $this->attributes['title'] = ucfirst($value);
    }

    public function getTitleAttribute($value)
    {
        return ucfirst($value);
    }
}

希望这能给你一些想法。