英文:
Laravel 9 Enum model casting not casting to string
问题
我在我的模型的AppLoanPurpose
字段上使用了一个枚举,它在数据库中存储一个整数。然后,该整数对应于某个值,例如,0 表示"Other",1 表示"Groceries"。
当我转换我的字段时,我仍然看到返回的是整数值而不是字符串。
我漏掉了什么?
<?php
namespace App\Enums\Applications\GB\Payday;
enum LoanPurpose: Int
{
case OTHER = 0;
case GROCERIES = 1;
public function label()
{
return match($this) {
self::OTHER => 'Other',
self::GROCERIES => 'Groceries'
};
}
}
模型
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Casts\Json;
use App\Enums\Applications\GB\Payday\LoanPurpose;
class ApplicationGBPayday extends Model
{
use HasFactory, SoftDeletes;
/**
* 与模型关联的表。
*
* @var string
*/
protected $table = 'application_gb_paydays';
/**
* 不可批量赋值的属性。
*
* @var array
*/
protected $guarded = [];
/**
* 应该被转换的属性。
*
* @var array<string, string>
*/
protected $casts = [
'AppLoanPurpose' => LoanPurpose::class,
];
/**
* 获取模型的申请
*/
public function application()
{
return $this->morphOne(Application::class, 'modelable');
}
}
你似乎忘记在LoanPurpose
枚举中调用label()
方法以获取字符串标签。在你的模型中,AppLoanPurpose
字段已经被正确地转换为LoanPurpose
枚举,但你需要调用label()
方法来获取相应的字符串值。例如:
$loanPurpose = ApplicationGBPayday::find(1)->AppLoanPurpose;
$label = $loanPurpose->label(); // 这将返回"Other"或"Groceries"
英文:
I'm using an Enum on my model's AppLoanPurpose
field which stores an integer in the database. The integer then corrosponds to something, for example, 0 means "Other" and 1 means "Groceries".
When I cast my field, I'm still seeing the integer value returned rather than my string.
What am I missing?
<?php
namespace App\Enums\Applications\GB\Payday;
enum LoanPurpose: Int
{
case OTHER = 0;
case GROCERIES = 1;
public function label()
{
return match($this) {
self::OTHER => 'Other',
self::GROCERIES => 'Groceries'
};
}
}
Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use App\Casts\Json;
use App\Enums\Applications\GB\Payday\LoanPurpose;
class ApplicationGBPayday extends Model
{
use HasFactory, SoftDeletes;
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'application_gb_paydays';
/**
* The attributes that aren't mass assignable.
*
* @var array
*/
protected $guarded = [];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'AppLoanPurpose' => LoanPurpose::class,
];
/**
* Get the model's application
*/
public function application()
{
return $this->morphOne(Application::class, 'modelable');
}
}
答案1
得分: 1
如果你真的想要使用 enum
,你必须将枚举视为常规对象。
enum LoanPurpose: Int {
case OTHER = 0;
case GROCERIES = 1;
public function label() {
return match($this) {
self::OTHER => 'Other',
self::GROCERIES => 'Groceries'
};
}
}
$enum = LoanPurpose::GROCERIES;
上面的代码将创建一个包含两个属性 name
和 value
的 LoanPurpose
实例。
= LoanPurpose {#xxxx
+name: "GROCERIES",
+value: 1,
}
调用这些属性:
// 输出:GROCERIES
$enum->name;
// 输出:1
$enum->value;
如果你向 LoanPurpose
添加一个方法,你仍然需要调用该方法以执行实际操作。在你的设置中,你只需调用 label
方法,它执行与你正在匹配的内容的 match
操作。
// 输出:Groceries
$enum->label();
如果你不想调用枚举实例的 name
或 value
,你可以使用属性访问器,比如 getAppLoanPurposeAttribute
并执行相同的操作。
use App\Enums\Applications\GB\Payday\LoanPurpose;
class ApplicationGBPayday extends Model {
// ...
public function getAppLoanPurposeAttribute($value) {
return return LoanPurpose::from($value)->name;
}
// ...
}
只需记住,你将失去枚举提供的任何有用性,因为 ApplicationGBPayday::AppLoanPurpose
永远不会返回一个 LoanPurpose
实例。
因此,以下是不可能的:
$ApplicationGBPayday::AppLoanPurpose == LoanPurpose::OTHER
正如 @silver 的回答中所述,你还可以使用 CastAttribute
接口,或者完全创建一个 Attribute
实例并返回它,我认为这会更容易。
更新
根据你提供的所有评论,ApplicationGBPayday
模型的属性 AppLoanPurpose
可以如下所示使用,就像你在问题中提到的示例一样。
$model = new ApplicationGBPayday([
'AppLoanPurpose' => 1 // 或 LoanPurpose::GROCERIES
]);
// 输出:1
$model->AppLoanPurpose->value;
// 输出:GROCERIES
$model->AppLoanPurpose->name;
// 输出:Groceries
$model->AppLoanPurpose->label();
如果你还没有使用它,我强烈建议使用 laravel-web-tinker 中的 tinker
进行测试,它为你提供了很多测试的空间。
英文:
If you really want to use enum
, you have to treat enum as a regular object.
enum LoanPurpose: Int {
case OTHER = 0;
case GROCERIES = 1;
public function label() {
return match($this) {
self::OTHER => 'Other',
self::GROCERIES => 'Groceries'
};
}
}
$enum = LoanPurpose::GROCERIES;
The above will create an instance of LoanPurpose
containing two attributes, name
and value
.
= LoanPurpose {#xxxx
+name: "GROCERIES",
+value: 1,
}
Calling those attributes
// will output: GROCERIES
$enum->name;
// will output 1
$enum->value;
If you add a method to LoanPurpose
, you still have to call that method in order to do something useful. In your setup, you just have to call the label
method which performs a match
with whatever you're matching.
// will output: Groceries
$enum->label();
If you do not want to call the name
or value
of the enum instance, you could use an attribute accessor like getAppLoanPurposeAttribute
and do just that.
use App\Enums\Applications\GB\Payday\LoanPurpose;
class ApplicationGBPayday extends Model {
// ...
public function getAppLoanPurposeAttribute($value) {
return return LoanPurpose::from($value)->name;
}
// ...
Just remember that you will have lost any usefulness an enum has to offer because ApplicationGBPayday::AppLoanPurpose
will never return a LoanPurpose
instance.
So the following would not be possible
$ApplicationGBPayday::AppLoanPurpose == LoanPurpose::OTHER
As stated in @silver's answer, you can also use the CastAttribute
interface, or entirely create an instance of Attribute
and return that instead, which I think would be much easier.
update
So reading all the comments you made, the attribute AppLoanPurpose
for model ApplicationGBPayday
can be used as follow as specified in the example given in your question.
$model = new ApplicationGBPayday([
'AppLoanPurpose' => 1 // or LoanPurpose::GROCERIES
]);
// will output: 1
$model->AppLoanPurpose->value;
// will output: GROCERIES
$model->AppLoanPurpose->name;
// will output: Groceries
$model->AppLoanPurpose->label();
If you're not already using it, I can really advice using tinker
with laravel-web-tinker from spatie. It gives you a lot of space to test around.
答案2
得分: 0
转换是将属性值转换为支持的数据类型,
你不能只是将属性强制转换为自己的数据类型,请查看支持的数据类型这里
在使用之前,你必须创建自己的自定义转换,否则,只需使用访问器和修改器
编辑
在 PHP 8.1 或更高版本中支持枚举转换
英文:
Casting is converting an attribute value into a supported data type,
You can't just cast an attribute to your own data type, check the supported data type here
You have to create your own custom cast before you can use it, otherwise, just use an Accessor and Mutator
EDIT
enum casting is supported in PHP 8.1 or above
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论