Laravel 6雄辩的模型序列化忽略了访问者

时间:2019-09-21 14:19:01

标签: php laravel eloquent

我正在将Laravel 6与SQL Server 2017数据库后端一起使用。在数据库中,我有一个名为PersonPhoto的表,其中有一个Photo列和一个Thumbnail列,其中照片和缩略图存储为VARBINARY。

我已经定义了以下Eloquent模型,使用两个访问器将图像转换为base64编码:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class PersonPhoto extends Model
{
    protected $connection = 'mydb';
    protected $table = 'PersonPhoto';
    protected $primaryKey ='PersonID';

    public function person(){

        return $this->belongsTo('App\Person', 'PersonID');

    }

    public function getPhotoAttribute($value){

        return base64_encode($value);

    }


    public function getThumbnailAttribute($value){

        return base64_encode($value);

    }

}

这在Blade模板中可以正常工作,但是当我尝试序列化为JSON或数组时,出现“格式错误的UTF-8字符,可能编码错误”错误,就像访问器被忽略并且原始数据正在被处理一样序列化。要解决此问题,我更改了模型:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class PersonPhoto extends Model
{
    protected $connection = 'mydb';
    protected $table = 'PersonPhoto';
    protected $primaryKey ='PersonID';

    //Added to hide from and add fields to serializer
    protected $hidden = ['Photo', 'Thumbnail'];
    protected $appends = ['encoded_photo', 'encoded_thumbnail'];

    public function person(){

        return $this->belongsTo('App\Person', 'PersonID');

    }

    public function getPhotoAttribute($value){

        return base64_encode($value);

    }

    public function getThumbnailAttribute($value){

        return base64_encode($value);

    }


    //Added these new accessors
    public function getEncodedPhotoAttribute(){

         return base64_encode($this->Photo);

    }

    public function getEncodedThumbnailAttribute(){

        return base64_encode($this->Thumbnail);

    }

}

这将隐藏序列化器中的原始“照片”和“缩略图”字段,并包括两个新的访问器。这似乎可以解决我的问题。

问题: 1)我怀疑Laravel的序列化程序是否会忽略我的访问器,这是设计使然吗? 2)尽管我的解决方法可行,但这是一种合理的方法还是我可能会遇到问题?有更好的方法吗?

谢谢

1 个答案:

答案 0 :(得分:1)

我认为您有两个问题:

首先,Laravel序列化要求您附加要包含的所有访问器-即使已经存在相同名称的属性。您没有在第一个示例中显式附加所需的值。

https://laravel.com/docs/5.8/eloquent-serialization#appending-values-to-json

第二,Laravel并不总是喜欢大写的属性名称。它很高兴地期望所有内容都是小写的(snake_case),并且基于一些快速测试,在涉及大小写时将适当的$value传递给访问器似乎有些麻烦。

但是,您可以修改访问器以直接调用该属性,而不必依靠Laravel来确定您要的内容并获得所需的结果。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class PersonPhoto extends Model
{
    protected $connection = 'mydb';
    protected $table = 'PersonPhoto';
    protected $primaryKey = 'PersonID';

    // add the desired appends for serialization
    protected $appends = ['Photo','Thumbnail'];

    public function person()
    {
        return $this->belongsTo('App\Person', 'PersonID');
    }

    public function getPhotoAttribute()
    {
        // access the attribute directly
        return base64_encode($this->attributes['Photo']);
    }


    public function getThumbnailAttribute()
    {
        // access the attribute directly
        return base64_encode($this->attributes['Thumbnail']);
    }

}

编辑:我实际上看到您在第二个示例中使用$this->Thumbnail$this->Photo做过类似的事情。我的示例具有相同的概念,但不依赖魔术方法。
__get/__set/__call performance questions with PHP