spatie / laravel-activitylog

Log activity inside your Laravel app

Home Page:https://docs.spatie.be/laravel-activitylog

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

invalid fetch of enum value when useAttributeRawValues

RecurLoop opened this issue · comments

Describe the bug

Everything works fine unless we apply the Arrayable interface to the enum (Laravel provides a convenient way to define how to convert the enum when calling toArray() on the model).

This causes LogsActivity::logChanges to try to retrieve ($model->getStorableEnumValue($changes[$attribute])) from the already converted value.

To Reproduce

  • create model with migration (one fillable text or integer column is required)
  • create an enum that implements the Arrayable interface (return type depends on column on model)
  • implement toArray function as public function toArray() { return $this->getValue(); }
  • add enum as caster to model
  • add LogsActivity trait to model (ActivityLogOptions - logsAll, useAttributeRawValues this enum attribute)
  • when you trigger logChanges (create/update events) on model php will report warning that you trying to get value/name(depends on enum implements BackedEnum) from string/int (depends on enum return type)

Expected behavior

LogsActivity::logChanges takes into account that the enum may already be a converted value.

Solution proposal

Modification of LogsActivity::logChanges function - replace
$changes[$attribute] = $model->getStorableEnumValue($changes[$attribute]);
to
$changes[$attribute] = $model->getStorableEnumValue( is_object($changes[$attribute]) ? $changes[$attribute] : $model->getEnumCaseFromValue($cast, $changes[$attribute]) );

Exception

PHP Warning: Attempt to read property "name" on string in /var/www/html/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/HasAttributes.php on line 1212

I will add information that the best use is when, in addition to the toArray function, we also define tryFromValue on the enum and overwrite the function on the model, as in

protected function getEnumCaseFromValue($enumClass, $value)
    {
        /**
         * Attribute is a trait for enums with defined tryFromValue function
         */
        if (in_array(Attribute::class, class_uses_recursive($enumClass))) {
            return $enumClass::tryFromValue($value) ?? $enumClass::from($value);
        }

        if (is_subclass_of($enumClass, BackedEnum::class)) {
            return $enumClass::from($value);
        }

        return constant($enumClass . '::' . $value);
    }

Dear contributor,

because this issue seems to be inactive for quite some time now, I've automatically closed it. If you feel this issue deserves some attention from my human colleagues feel free to reopen it.