Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Illuminate\Database\Eloquent\Casts\ArrayObject not transforming into array #913

Closed
qbaniewiadomski opened this issue Dec 20, 2024 · 2 comments

Comments

@qbaniewiadomski
Copy link

qbaniewiadomski commented Dec 20, 2024

✏️ Describe the bug
In User model I have cast database column roles (which contains enum values in array format e.g. ["ADMIN","EMPLOYEE"]) to ArrayObject with Enums.

Illuminate\Database\Eloquent\Casts\ArrayObject {#681 // app/Http/Controllers/UserController.php:118
  storage: array:1 [
    0 => 
App\Enum
\
UserRole {#687
      +name: "ADMIN"
      +value: "ADMIN"
    }
  ]
  flag::STD_PROP_LIST: false
  flag::ARRAY_AS_PROPS: false
  iteratorClass: "ArrayIterator"
}

When trying to return it in DTO as array, I receive:

App\\DTO\\Response\\User\\UserDto::__construct(): Argument #8 ($roles) must be of type array, Illuminate\\Database\\Eloquent\\Casts\\ArrayObject given, called in /app/vendor/spatie/laravel-data/src/Resolvers/DataFromArrayResolver.php on line 95

It worked fine in version 4.6.0
Currently I did workaround:

final class UserDto extends Data
{
    /** @var array<UserRole> $roles */
    #[Computed]
    public readonly array $roles;

    public function __construct(
        ArrayObject $roles,
    ) {
        $this->roles       = $roles->getArrayCopy();
    }
}

↪️ To Reproduce

User Model:

class User extends Authenticatable
{
[...]
    protected function casts(): array
    {
        return [
            'roles' => AsEnumArrayObject::class . ':' . UserRole::class,
        ];
    }
[...]
}

UserDto Class:

final class UserPreviewDto extends Data
{
    [...]
    /** @param array<UserRole> $roles */
    public function __construct(
        [...]
        public readonly array $roles = [],
    ) {
        [...]
    }
}

Than: UserDto::from($user)

✅ Expected behavior
Illuminate\Database\Eloquent\Casts\ArrayObject should be casted to array, e.g.:

["ADMIN"]

🖥️ Versions

Laravel: 11.33.2
Laravel Data: 4.11.1
PHP: 8.3.14

@rust17
Copy link
Contributor

rust17 commented Dec 24, 2024

After several hours of debugging, I traced the issue to this change. However, I couldn't find documentation supporting this usage. I make a PR to support if this functionality is desired.

@rubenvanassche
Copy link
Member

This feels like valid behavior to me since you're using an ArrayObject cast within Eloquent which will return an ArrayObject, if you want this to work use an ArrayObject within your Data class. No idea why Laravel doesn't support casting into an array of enums but I don't think laravel-data should change types on the fly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants