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

Auto lazy #831

Merged
merged 5 commits into from
Jan 24, 2025
Merged

Auto lazy #831

merged 5 commits into from
Jan 24, 2025

Conversation

rubenvanassche
Copy link
Member

Writing Lazy properties can be a bit cumbersome. It is often a repetitive task to write the same code over and over again while the package can infer almost everything.

Let's take a look at an example:

class UserData extends Data
{
    public function __construct(
        public string $title,
        public Lazy|SongData $favorite_song,
    ) {
    }

    public static function fromModel(User $user): self
    {
        return new self(
            $user->title,
            Lazy::create(fn() => SongData::from($user->favorite_song))
        );
    }
}

The package knows how to get the property from the model and wrap it into a data object, but since we're using a lazy property, we need to write our own magic creation method with a lot of repetitive code.

In such a situation auto lazy might be a good fit, instead of casting the property directly into the data object, the casting process is wrapped in a lazy Closure.

This makes it possible to rewrite the example as such:

#[AutoLazy]
class UserData extends Data
{
    public function __construct(
        public string $title,
        public Lazy|SongData $favorite_song,
    ) {
    }
}

While achieving the same result!

Auto Lazy wraps the casting process of a value for every property typed as Lazy into a Lazy Closure when the AutoLazy attribute is present on the class.

It is also possible to use the AutoLazy attribute on a property level:

class UserData extends Data
{
    public function __construct(
        public string $title,
        #[AutoLazy]
        public Lazy|SongData $favorite_song,
    ) {
    }
}

The auto lazy process won't be applied in the following situations:

  • When a null value is passed to the property
  • When the property value isn't present in the input payload and the property typed as Optional
  • When a Lazy Closure is passed to the property

@jonjakoblich
Copy link

Really looking forward to this feature. Is it going to be in an upcoming release?

# Conflicts:
#	src/Support/Factories/DataPropertyFactory.php
#	tests/CreationTest.php
#	tests/Support/DataPropertyTest.php
@rubenvanassche rubenvanassche merged commit fa6782c into main Jan 24, 2025
24 checks passed
@Nielsvanpach Nielsvanpach deleted the auto-lazy branch January 24, 2025 15:40
@francoism90
Copy link
Contributor

francoism90 commented Jan 25, 2025

@rubenvanassche This seems to cause some issues:

Typed property Spatie\LaravelData\Support\DataProperty::$autoLazy must not be accessed before initialization 

Example of the DataObject:

class ObjectData extends Data
{
    public function __construct(
        public InputData $input,
        public Optional|string $input_config,
    ) {}
}

I'm trying to access something in input:

$object->input->foo; // this sub value has Optional|string $foo

@francoism90
Copy link
Contributor

Sorry for the noise!

If anyone has this, make sure caches are cleared or rebuilt:

php artisan data:cache-structures

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

Successfully merging this pull request may close these issues.

3 participants