Skip to content
New issue

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

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

Already on GitHub? # to your account

Add support for AsCollection::using and AsEnumCollection::of casts #1577

Merged
merged 3 commits into from
Oct 28, 2024

Conversation

uno-sw
Copy link
Contributor

@uno-sw uno-sw commented Aug 2, 2024

Summary

When you have the casts definition in a model like:

protected function casts(): array
{
    return [
        'options' => AsCollection::using(OptionCollection::class),
        'statuses' => AsEnumCollection::of(ServerStatus::class),
    ];
}

then php artisan ide-helper:models command will generate the following PHPDoc for the model:

/**
 * @property OptionCollection $options
 * @property \Illuminate\Support\Collection<int, ServerStatus> $statuses
 */

It also supports styles prior to Laravel 11:

protected $casts = [
    'options' => AsCollection::class.':'.OptionCollection::class,
    'statuses' => AsEnumCollection::class.':'.ServerStatus::class,
];

Related to #1553

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
  • Misc. change (internal, infrastructure, maintenance, etc.)

Checklist

  • Existing tests have been adapted and/or new tests have been added
  • Add a CHANGELOG.md entry
  • Update the README.md
  • Code style has been fixed via composer fix-style

@uno-sw uno-sw changed the title Add support for AsCollection::of and AsEnumCollection::of casts Add support for AsCollection::using and AsEnumCollection::of casts Aug 2, 2024
@uno-sw
Copy link
Contributor Author

uno-sw commented Aug 12, 2024

Hello @barryvdh and @mfn

I hope this message finds you well. I just wanted to bring to your attention that this pull request is ready for review. As this is my first contribution to the repository, I am eager to hear your feedback and make any necessary improvements.

Please let me know if there is anything else I should address. I look forward to your review.

Thank you for your time!

@jackwh
Copy link

jackwh commented Sep 16, 2024

@uno-sw Thanks for the PR, this would make a great addition! Hopefully it gets merged soon 🤞

For anyone else wanting this sooner, it can be solved by adding this hook I quickly put together to the ide-helper.php config file. Note that this hook just assumes matching columns are nullable, unlike the PR.

<?php

namespace App\Models\Hooks;

use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Illuminate\Database\Eloquent\Casts\AsCollection;
use Illuminate\Database\Eloquent\Casts\AsEnumCollection;
use Illuminate\Database\Eloquent\Model;

class ApplyCustomCollectionHints implements \Barryvdh\LaravelIdeHelper\Contracts\ModelHookInterface
{
    /**
     * When a Model casts an attribute with AsCollection::using(...) or AsEnumCollection::using(...),
     * we'll override the default type hints to be more precise.
     *
     * TODO this hook can be removed once this PR is merged: https://github.com/barryvdh/laravel-ide-helper/pull/1577
     */
    public function run(ModelsCommand $command, Model $model): void
    {
        foreach ($model->getCasts() as $name => $type) {

            // AsCollection::using(...)
            if (str($type)->startsWith(AsCollection::class . ':')) {
                $usedType = str($type)->afterLast(':')->start('\\')->toString();

                if (class_exists($usedType)) {
                    $command->setProperty(name: $name, type: $usedType . '|null');
                }
            }

            // AsEnumCollection::using(...)
            if (str($type)->startsWith(AsEnumCollection::class . ':')) {
                $baseType = str(\Illuminate\Support\Collection::class)->start('\\')->toString();
                $usedType = str($type)->afterLast(':')->start('\\')->toString();

                if (class_exists($usedType)) {
                    $command->setProperty(
                        name: $name,
                        type: $baseType . '<int, ' . $usedType . '>|null'
                    );
                }
            }
        }
    }
}

@barryvdh barryvdh merged commit d6fb790 into barryvdh:master Oct 28, 2024
@uno-sw uno-sw deleted the patch-1 branch October 29, 2024 07:43
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants