Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >当使用空间/拉拉模型状态时,Laravel属性不转换为对象。

当使用空间/拉拉模型状态时,Laravel属性不转换为对象。
EN

Stack Overflow用户
提问于 2021-12-23 09:25:45
回答 1查看 653关注 0票数 2

在使用Spatie的模型状态库时,我遇到了一个问题。我不认为这是一个bug,但它的行为并不像预期的那样,尽管只是在我的一个控制器中。我们使用的是旧版本的代码,目前无法更新到最新版本。

问题是"state“字段没有被转换到Spatie\ModelStates\State派生对象,而是以字符串的形式返回。因此,当我尝试转换到一个新的状态时,我会得到一个异常:“调用字符串上的成员函数transitionTo()”。

但是,代码的其他部分使用相同的模型,并且转换工作正常,状态被转换为正确的类。我只是不明白为什么这个控制器会引起问题。

从我自己的抽象类派生出来的状态

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<?php

namespace App\States\ShiftPattern;

use Spatie\ModelStates\State;

abstract class ShiftPatternBaseState extends State
{
    public static array $states = [
        Approved::class,
        Draft::class,
        PendingApproval::class,
        Rejected::class,
    ];
}

即使我在基类中注册状态,它们也在同一个文件夹中。迁移将status字段添加到数据库表中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    public function up()
    {
        Schema::table('shift_patterns', function (Blueprint $table) {
            $table->string('status')->default('draft')->after('booking_pay_rate_id');
        });
    }

我的模型实现了HasStates

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class ShiftPattern extends Model
{
    use HasStates, LogsActivity, UserPermissions;
    ...
    public function registerStates(): void
    {
        $this->addState('status', ShiftPatternBaseState::class)
            ->default(Draft::class)
            ->allowTransition([Draft::class, Rejected::class], PendingApproval::class, ToPendingApproval::class)
            ->allowTransition(PendingApproval::class, Approved::class, PendingApprovalToApproved::class)
            ->allowTransition(PendingApproval::class, Rejected::class, ToRejected::class);
    }
    ...
}

这个问题发生在我正在更新的一个控制器中。它目前处理一个API调用来创建一个新的ShiftPattern并将它附加到一个Booking模型上,这个模型可以工作。BookingShiftPattern之间有一对多的关系。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// CreateShiftPatternRequest has the Booking object ($request->record) and attributes ($request->attributes) to create the ShiftPattern

public function createShiftPattern(CreateShiftPatternRequest $request)
{
    $this->authorize('editShiftPatterns', $request->record);

    $shiftPattern = $request->record->shiftPatterns()->create($request->attributes());

    return $this->reply()->content($shiftPattern, [], $this->getMeta('bookings.shift-pattern.create'));
}

新的ShiftPattern是在"Pending“状态下创建的,但是有些预订并不要求它们被”批准“,所以我想将它们直接移到”批准“状态。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public function createShiftPattern(CreateShiftPatternRequest $request)
{
    ...
    $shiftPattern = $request->record->shiftPatterns()->create($request->attributes());
    if (!$request->record->booking_must_be_approved) {
        $shiftPattern->transitionTo(Approved::class);
    }
    return $this->reply()->content($shiftPattern, [], $this->getMeta('bookings.shift-pattern.create'));
}

但是,我一直收到错误“调用字符串上的成员函数transitionTo()”,在transitionTo调用中,状态字段被库解析后就会发生这种错误。正如我所说的,在其他情况下,这很好,但是在这个控制器中,state字段不会自动转换为一个对象。

我认为模型可能没有正确地“引导”来设置类转换,所以我公开了一个函数,允许控制器调用bootIfNotBooted,但是在里面它跳过初始化,因为它已经被引导了。然后,我尝试从数据库中刷新和重新加载ShiftPattern,看看这是否能解决这个问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    ...
    $shiftPattern = $request->record->shiftPatterns()->create($request->attributes());

    // Attempt 1 - refresh model
    $shiftPattern->refresh();
    // Attempt 2 - reload model
    $newShiftPattern = ShiftPattern::find($shiftPattern->id); 
    ...

这两种方法都不起作用,状态字段仍然作为字符串返回。

我还尝试创建模型,而不是将其与预订联系起来,但这也没有解决问题。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    $shiftPattern = ShiftPattern::create($request->attributes());
    if (!$request->record->booking_must_be_approved) {
        $shiftPattern->transitionTo(Approved::class);
    }
    $request->record->shiftPatterns()->save($shiftPattern);
    ...

有人知道为什么会发生这种事吗?我真的不认为它是ModelStates库中的一个bug,因为它适用于tinker和我的代码的其他部分,它似乎是一个Laravel属性强制转换问题。

我也在包的github讨论上发布了这个问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-04 06:32:06

这个问题是由从传入的属性创建status字段时填充的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ShiftPattern::create($request->attributes());

create被调用时,Laravel构造一个新的对象,然后从传递的数组中填充属性。在这种情况下,API的调用方包含状态的名称(pending-approval),因此在构造类并将status字段设置为默认状态(作为对象)之后,属性将被字符串“未决-批准”覆盖--因此在尝试转换到新状态时出现错误。

我看到的解决办法是:

  1. 不要允许状态字段是可填充的-让对象使用默认状态创建,然后转换到所需的状态。此方法还确保调用任何转换类。
  2. 修复状态映射--在我的例子中,问题是由于另一个开发人员不再想要使用draft状态(然后转换到pending-approval)并直接跳转到pending-approval而引起的,但是更改是在没有考虑其影响的情况下进行的。应该删除draft状态并重构代码。
  3. 在state属性上实现一个mutator -- mutator将允许使用状态名称并将其转换为状态对象。

对于解决方案3,mutator可以使用库函数resolveStateClass

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public function setStatusAttribute($status)
{
    if (is_string($status)) {
        $stateClass = ShiftPatternBaseState::resolveStateClass($status);
        $status = class_exists($stateClass)
                    ? new $stateClass($this)
                    : (new ReflectionClass(self::getDefaultStateFor('status')))->newInstance($this);
    }

    $this->attributes['status'] = $status;
}

当状态使用字符串时,基态检查它是否可以解析为类(可以使用名称或类字符串)。解析函数返回的字符串要么是完全限定的类名,要么是与已知状态类不匹配的字符串,或者是传入的字符串。

检查字符串结果以查看类是否存在,意味着我们可以创建该状态类的实例,也可以创建默认状态。无论哪种方式,对象上的属性现在都是正确的,我们可以在它上调用transitionTo

我将使用这个mutator来快速修复我遇到的问题,但是接下来我需要返回并重构代码(选项2),以删除draft状态,并在将来使用pending-approval状态作为默认状态。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70465485

复制
相关文章
当不使用会话状态时禁用它
并不是所有的应用程序或页都需要针对于具体用户的会话状态,您应该对任何不需要会话状态的应用程序或页禁用会话状态。
Java架构师必看
2021/03/22
5090
Promise对象状态属性介绍
当创建一个Promise对象时,初始状态是pending(待定)状态。这表示Promise对象尚未完成,异步操作仍在进行中。
堕落飞鸟
2023/05/23
4720
当css属性width设为100%时
  平常在写页面html代码时,经常会使用到width:100%来使控件宽度为父控件的内容宽度。但如果父控件为body,而且没有明确设置body的宽度,那么就会出现以下的情况了。   代码: 1 <body> 2 <div style="background:#888;width:100%;height:200px"> 3 <div style="width:1000px;height:100px;margin:0 auto;border:solid 1px red"></div> 4 </di
^_^肥仔John
2018/01/18
1.4K0
当css属性width设为100%时
Java对象转JSON时如何动态的增删改查属性
日常开发中少不了 JSON 处理,少不了需要在 JSON 中添加额外字段或者删除特定字段的需求。今天我们就使用Jackson类库来实现这个功能。
码农小胖哥
2020/10/30
3K0
Java对象转JSON时如何动态的增删改查属性
JSP request对象、response对象、contentType属性,HTTP状态码
1.request.getProtocol(); 获取客户向服务器提交信息所使用的通信协议,比如:http/1.1
全栈程序员站长
2022/09/09
1.1K0
对象迁移空间对索引状态的影响
上篇文章介绍了迁移表、索引对象的操作: http://blog.csdn.net/bisal/article/details/50804714 发现漏了一个细节,就是表、LOB对象移动后索引的状态。
bisal
2019/01/29
5030
强化学习 9: 当 Action 的空间连续时
之前骑自行车的例子中,action 可以是向左或者向右,现在的话可能是一个实数值的区间。
杨熹
2018/12/17
1.2K0
强化学习 9: 当  Action 的空间连续时
使用 AutoMapper 自动映射模型时,处理不同模型属性缺失的问题
使用 AutoMapper 可以很方便地在不同的模型之间进行转换而减少编写太多的转换代码。不过,如果各个模型之间存在一些差异的话(比如多出或缺少一些属性),简单的配置便不太行。本文帮助你解决这个问题。
walterlv
2023/10/23
6710
XMLHttpRequest对象的status属性状态吗
在做异步操作的时候,我们通常需要判断返回的状态码来判断服务器返回的数据是否正常,下面是常见的一些状态码和对应的含义。
全栈程序员站长
2022/07/19
5790
jackson简单使用,对象转json,json转对象,json转list
添加jackson依赖: // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.8.2' // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind
Ryan-Miao
2018/03/13
7.8K0
json转对象时一直报错
问题:json格式的请求体经controller控制器会自动转换成对象格式。可是的json请求的key和对应的类的字段是一模一样的,发送请求总是显示400错误,估计是请求体错误。可是并没有发现错误啊,请求的字段都是复制的,百思不得其解,只能逐个定位,一步一步的找错。
全栈程序员站长
2022/08/05
5500
【说站】laravel模型中的$casts属性转换
按照以往的操作,在create的时候,先手动对特定的字段进行json_encode,然后再create;
很酷的站长
2022/11/24
1.8K0
【说站】laravel模型中的$casts属性转换
jackson设置读取属性时使用大写序列化属性时使用小写
jackson是一种使用广泛的json序列化库,虽然性能上可能不如fastjson,但是从其标准性以及安全性上来看(近一年爆出了不少fastjson的漏洞),下面就介绍下本文的主题,jackson序列化以及反序列化时可能用到的几个注解:
johnhuster的分享
2022/03/28
1.3K0
Java中当对象不再使用时,不赋值为null会导致什么后果 ?
点击上方蓝色“程序猿DD”,选择“设为星标” 回复“资源”获取独家整理的学习资料! 作者 | zhantong 来源 | https://www.polarxiong.com 前言 许多Java开发者都曾听说过“不使用的对象应手动赋值为null“这句话,而且好多开发者一直信奉着这句话;问其原因,大都是回答“有利于GC更早回收内存,减少内存占用”,但再往深入问就回答不出来了。 鉴于网上有太多关于此问题的误导,本文将通过实例,深入JVM剖析“对象不再使用时赋值为null”这一操作存在的意义,供君参考。本文尽量
程序猿DD
2023/04/17
6410
Java中当对象不再使用时,不赋值为null会导致什么后果 ?
java对象转换为json字符串_复杂json字符串转对象
在学习如何编写基于Java的软件时,开发人员遇到的第一个障碍就是如何将其代码与其他软件连接。 这通常是JSON的来源。虽然您可能是Java向导,但JSON是另一种动物。 无论如何,这篇博客文章解释了完成工作所需的一切。
全栈程序员站长
2022/09/30
8.9K0
java对象转换为json字符串_复杂json字符串转对象
Spring使用p名称空间配置属性
Spring的p标签是基于XML Schema的配置方式,目的是为了简化配置方式。
大黄大黄大黄
2018/09/14
9330
Spring使用p名称空间配置属性
Laravel Model常用属性
$table = ‘应当操作的表名’; $primaryKey= ‘主键’; $timestamps = false;//是否创建crearte_at与update_at字段 $fillable = [ ‘可批量填充的字段’];
切图仔
2022/09/08
4880
Java对象转Map,Map转对象
两个方法mapToBean()和beanToMap()直接copy过去就能用,map转对象的时候一定要注意值类型
全栈程序员站长
2022/07/01
3.5K0
spring开发_使用p名称空间配置属性
http://www.cnblogs.com/hongten/gallery/image/112563.html
Hongten
2018/09/13
4550
点击加载更多

相似问题

使用空间/拉拉的Laravel 5.1 ACL -许可

10

当使用范围属性时,$watch不监视模型

10

错误消息:当对象包含属性时,对象不包含属性

23

如何在使用Laravel检索模型/对象时动态隐藏其属性

20

laravel转储模型查询

10
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文