如何防止在Laravel中无提示丢弃属性?

sz81bmfz  于 2023-03-09  发布在  其他
关注(0)|答案(1)|浏览(132)

我对PHP和我正在调试的几乎没有文档记录的遗留代码库都很陌生。我的一个模型上的一个属性在DB保存时被设置为NULL,我不清楚为什么。这个问题主要是关于我试图封锁其中一种可能性。
(It可能是类型转换错误-模型将字段视为整数,但DB认为它是字符串,或者某些代码设置了字段,而其他代码没有设置,或者有大量无法访问的代码,可能还有其他一些可能性。我跟踪代码,但它是几十个未记录的专有代码文件,所以请耐心听我说,在这种情况下,很坚韧做出一个最小的可重复示例。)
我看到了这篇关于配置Eloquentstrictness的文章,“静默丢弃”这个属性听起来很像“将其设置为null而不记录异常”,所以我想我应该试试。(关注的领域列在其特定模型的protected $fillable属性中,所以我也可能找错了对象...)根据本文,我的(预先存在的,可能正常工作)app/Providers/AppServiceProvider.php现在包含此导入:

use Illuminate\Database\Eloquent\Model;

还包含以下函数定义:

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    $this->trackDatabaseEvents();
    Schema::defaultStringLength(191);
    Model::preventSilentlyDiscardingAttributes(! $this->app->isProduction());
}

我只添加了第三行,它直接从上面的how-to复制而来,也出现在in a couple其他上下文中...但是当我尝试编译应用程序时,我得到

#23 10.45 Generating optimized autoload files
#23 12.89 > Illuminate\Foundation\ComposerScripts::postAutoloadDump
#23 12.91 > @php artisan package:discover --ansi
#23 13.08 [2023-01-24 14:27:57] production.ERROR: SQLSTATE[08006] [7] could not translate host name "postgres" to address: Name or service not known (SQL: select * from "applications" limit 1)  
#23 13.11 [2023-01-24 14:27:57] production.ERROR: [0] "Cannot instantiate abstract class Illuminate\Database\Eloquent\Model" on line 59 of file /app/app/Providers/AppServiceProvider.php  
#23 13.11 
#23 13.11    Error 
#23 13.11 
#23 13.11   Cannot instantiate abstract class Illuminate\Database\Eloquent\Model
#23 13.11 
#23 13.11   at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2144
#23 13.12     2140▕      * @return mixed
#23 13.12     2141▕      */
#23 13.12     2142▕     public static function __callStatic($method, $parameters)
#23 13.12     2143▕     {
#23 13.12   ➜ 2144▕         return (new static)->$method(...$parameters);
#23 13.12     2145▕     }
#23 13.12     2146▕ 
#23 13.12     2147▕     /**
#23 13.12     2148▕      * Convert the model to its string representation.
#23 13.12 
#23 13.12   1   app/Providers/AppServiceProvider.php:59
#23 13.12       Illuminate\Database\Eloquent\Model::__callStatic()
#23 13.12 
#23 13.12       +7 vendor frames 
#23 13.12   9   [internal]:0
#23 13.12       Illuminate\Foundation\Application::Illuminate\Foundation\{closure}()
#23 13.14 Script @php artisan package:discover --ansi handling the post-autoload-dump event returned with error code 1

我 * 正在 * 使用Postgres,如果我在 Boot 中复制出一个额外的命令,我就可以成功地编译应用程序:Model::preventSilentlyDiscardingAttributes(! $this->app->isProduction());。这两种情况下的编译都是通过Docker进行的,崩溃发生在RUN composer install。下面是一个经过裁剪的Docker文件版本,以便用户检查版本号等:

FROM ubuntu:focal as build

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
    && apt-get install -y software-properties-common \
    && add-apt-repository -y ppa:ondrej/php \
    && apt-get install -y php8.1-fpm php8.1-cli php8.1-curl \
       php8.1-mbstring php8.1-xml php8.1-pgsql php8.1-intl php8.1-zip php8.1-gd \
       php8.1-gmagick php8.1-dev php-pear \
       libpq-dev libevent-dev libssl-dev netcat unzip \
    && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
    && printf "\n" | pecl install event

WORKDIR /app

< a bunch of COPY commands; trimmed for space >

RUN composer install
    # --ignore-platform-reqs \
    # --no-interaction \
    # --no-plugins \
    # --no-scripts \
    # --prefer-dist

我不知道为什么这些选项被注解掉了,但也许可以找到答案。我在这里包含它们是为了防止大家认为我有其中一个选项或其他选项。无论是否崩溃,这些选项都是相同的,并且被注解掉了。唯一的变化是AppServiceProvider.phpModel::preventSilentlyDiscardingAttributes行的存在/不存在
另外,有一条评论问到了docker-compose.yml。有这样一个文件,但是我需要在“组合”多个图像之前构建图像。当我启用或禁用这一行时,docker-compose中引用的其他图像都没有运行。
另一条评论让我开始研究Composer脚本,在浏览了那一页之后,我查看了我的composer.json

"scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    },

我不知道这是否导致了这个问题,但是“@php artisan package:discover --ansi“确实出现在前面引用的回溯的末尾。
为了提供关于字段“data_source“的更多细节,它的奇怪行为使我开始沿着这条路走下去:模型类定义之前的注解块包含* @property mixed $data_source行。代码中分配给字段的值总是使用类中定义的常量,并且这些常量总是整数。它旨在充当短枚举类型,有三个值(除了null):还有一个类常量数组,它将这三个整数中的两个Map为字符串,但在读取和保存过程中使用该数组是不一致的,并且Map名称的grep没有显示任何类似自动类型转换的内容。它显示列数据类型为“字符变化(10)"。DB中的所有记录在该列中具有NULL值。一些保存/更新记录的代码专门设置了该列;所以我添加了日志消息,试图找出实际涉及的代码片段。
PHP版本为8.1.16,ORM为Laravel框架8.83.27
感谢您的关注和帮助。

umuewwlo

umuewwlo1#

这个错误是由于preventSilentlyDiscardingAttributes不存在于您正在使用的Laravel框架版本中。它是在9.28.0中添加的(但没有完全按预期工作,后来得到了修复)。
如果升级到一个新版本的框架是不可能的,你可以考虑一个类似于我在我的项目中使用的方法,即把逻辑向后移植到你的模型类中。
我创建了一个BaseModel,其中包含在preventSilentDiscardingAttributes中实现的相应逻辑,并将其应用到开发环境中:

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\MassAssignmentException;

class BaseModel extends Model {
    public function fill( array $attributes ) {

    if ( env( 'APP_ENV' ) !== 'production' ) {
        $fillable = $this->fillableFromArray( $attributes );

        foreach ( $fillable as $key => $value ) {
            // The developers may choose to place some attributes in the "fillable" array
            // which means only those attributes may be set through mass assignment to
            // the model, and all others will just get ignored for security reasons.
            if ( ! $this->isFillable( $key ) ) {
                throw new MassAssignmentException( sprintf(
                    'Add [%s] to fillable property to allow mass assignment on [%s].',
                    $key, get_class( $this )
                ) );
            }
        }
        if ( count( $attributes ) !== count( $fillable ) ) {
            $keys = array_diff( array_keys( $attributes ), array_keys( $fillable ) );

            throw new MassAssignmentException( sprintf(
                'Add fillable property [%s] to allow mass assignment on [%s].',
                implode( ', ', $keys ),
                get_class( $this )
            ) );
        }
    }
        parent::fill( $attributes );

        return $this;
    }
}

然后,我为所有模型类扩展这个BaseModel

相关问题