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

Add better support for macros and mixins #1006

Merged
merged 1 commit into from
Sep 6, 2020
Merged

Add better support for macros and mixins #1006

merged 1 commit into from
Sep 6, 2020

Conversation

domkrm
Copy link
Contributor

@domkrm domkrm commented Aug 8, 2020

I have added macro support for all macroable classes, not only the alias classes.
But this only works if the macros are declared in any loaded service provider and type hinting is used.
Also no description is possible, only parameter and return types.

Copy link
Collaborator

@mfn mfn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey 👋 very cool approach!

I left some in-line feedback.


Also: All / some? of the whitespace changes in resources/views/helper.php generate a vastly differently indented _ide_helper.php file:

  • run master, generate _ide_helper.php , make a copy
  • run your PR, generate _ide_helper.php
  • diff them
  • 💥

People tend to commit this file and those two versions are essentially "uncomparable".

I don't want to say it's the most important thing in the world, but some of those changes just look unnecessary anyway, so you might want to massage this a bit.

Maybe also rebase against master, there were some formatting changes already, creating merge conflicts currently.


Seeing that I had some exceptions thrown my way, we definitely should come up with some tests for this.

src/Macro.php Outdated

// Add macro parameters
foreach ($method->getParameters() as $parameter) {
$type = $parameter->hasType() ? $parameter->getType() : 'mixed';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

./artisan ide-helper:generate

   ErrorException

  Function ReflectionType::__toString() is deprecated

  at vendor/barryvdh/laravel-ide-helper/src/Macro.php:45
    41|
    42|         // Add macro parameters
    43|         foreach ($method->getParameters() as $parameter) {
    44|             $type = $parameter->hasType() ? $parameter->getType() : 'mixed';
  > 45|             $type .= $parameter->hasType() && $parameter->getType()->allowsNull() ? '|null' : '';
    46|
    47|             $name = $parameter->isVariadic() ? '...' : '';
    48|             $name .= '$' . $parameter->getName();
    49|

      +21 vendor frames
  22  artisan:37
      Illuminate\Foundation\Console\Kernel::handle()

I guess this is dependent on the PHP version? It's "just" a deprecation but people might run with E_ALL and thus trip over this.

This fixes it:

Suggested change
$type = $parameter->hasType() ? $parameter->getType() : 'mixed';
$type = $parameter->hasType() ? $parameter->getType()->getName() : 'mixed';

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed this to your suggestion.

src/Macro.php Outdated

// Add macro return type
if ($method->hasReturnType()) {
$type = $method->getReturnType();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I have the same issue:

$ ./artisan ide-helper:generate

   ErrorException

  Function ReflectionType::__toString() is deprecated

  at vendor/barryvdh/laravel-ide-helper/src/Macro.php:56
    52|
    53|         // Add macro return type
    54|         if ($method->hasReturnType()) {
    55|             $type = $method->getReturnType();
  > 56|             $type .= $method->getReturnType()->allowsNull() ? '|null' : '';
    57|
    58|             $this->phpdoc->appendTag(Tag::createInstance("@return {$type}"));
    59|         }
    60|     }

      +21 vendor frames
  22  artisan:37
      Illuminate\Foundation\Console\Kernel::handle()
Suggested change
$type = $method->getReturnType();
$type = $method->getReturnType()->getName();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed this to your suggestion.

@domkrm
Copy link
Contributor Author

domkrm commented Aug 23, 2020

I have adopted all of your suggestions. But I also have changed many things because I noticed that classes could be duplicate in the helper file if they have macros (Facades, Arr, Str, ...).

Copy link
Collaborator

@mfn mfn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approach LGTM and I only have some minor feedback; additionally:

  • can you please rebase on master and solve the merge conflict?
  • re-add the nice README entry you had?
  • add a changelog entry?
    Yes, we now have a changelog 😄

Thanks and sorry for the long delay, rest assured unless I get hit by a bus, the next feedback will be quicker 🤞

*/
protected function getMacroableClasses(Collection $aliases)
{
return collect(get_declared_classes())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collect

Please don't use global helpers, it's a bad practice doing this in libraries. None of the helpers from Illuminate\Support\helpers.php is currently in use.

Using the collection of course is fine!

$traits = class_uses($class);

// Filter only classes with the macroable trait
return isset($traits['Illuminate\Support\Traits\Macroable']);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Illuminate\Support\Traits\Macroable::class and also import it, thanks!

Comment on lines +38 to +42
$type = $parameter->hasType() ? $parameter->getType()->getName() : 'mixed';
$type .= $parameter->hasType() && $parameter->getType()->allowsNull() ? '|null' : '';

$name = $parameter->isVariadic() ? '...' : '';
$name .= '$' . $parameter->getName();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very clean but also duplicate code of what happens in \Barryvdh\LaravelIdeHelper\Method::getParameters

  • the other method seems more feature-complete though I can't say if this is necessary
  • but it's written in a way which makes it not easily re-usable AFAICS, i.e. you just can't call it.

Would you be interested comparing the the two approaches and see if yours is missing something? E.g. default values seems to be handled, etc.


Unifying this is topic for a different PR IMHO and shouldn't be done here.

$reflection = new ReflectionClass($class);

// Filter out internal classes and class aliases
return !$reflection->isInternal() && $reflection->getName() == $class;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return !$reflection->isInternal() && $reflection->getName() == $class;
return !$reflection->isInternal() && $reflection->getName() === $class;


// Filter out aliases
return !$aliases->first(function (Alias $alias) use ($class) {
return $alias->getExtends() == $class;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return $alias->getExtends() == $class;
return $alias->getExtends() === $class;

@mfn
Copy link
Collaborator

mfn commented Sep 5, 2020

Btw, do we still need the code in \Barryvdh\LaravelIdeHelper\Alias::detectMethods 🤔 What's the difference?

            // Check if the class is macroable
            $traits = collect($reflection->getTraitNames());
            if ($traits->contains('Illuminate\Support\Traits\Macroable')) {
                $properties = $reflection->getStaticProperties();
                $macros = isset($properties['macros']) ? $properties['macros'] : [];
                foreach ($macros as $macro_name => $macro_func) {
                    if (!in_array($macro_name, $this->usedMethods)) {
                        // Add macros
                        $this->methods[] = new Macro(
                            $this->getMacroFunction($macro_func),
                            $this->alias,
                            $reflection,
                            $macro_name,
                            $this->interfaces
                        );
                        $this->usedMethods[] = $macro_name;
                    }
                }
            }

@domkrm
Copy link
Contributor Author

domkrm commented Sep 5, 2020

I have done a rebase and applied all your suggestions.

@domkrm
Copy link
Contributor Author

domkrm commented Sep 5, 2020

Btw, do we still need the code in \Barryvdh\LaravelIdeHelper\Alias::detectMethods 🤔 What's the difference?

            // Check if the class is macroable
            $traits = collect($reflection->getTraitNames());
            if ($traits->contains('Illuminate\Support\Traits\Macroable')) {
                $properties = $reflection->getStaticProperties();
                $macros = isset($properties['macros']) ? $properties['macros'] : [];
                foreach ($macros as $macro_name => $macro_func) {
                    if (!in_array($macro_name, $this->usedMethods)) {
                        // Add macros
                        $this->methods[] = new Macro(
                            $this->getMacroFunction($macro_func),
                            $this->alias,
                            $reflection,
                            $macro_name,
                            $this->interfaces
                        );
                        $this->usedMethods[] = $macro_name;
                    }
                }
            }

Yes, this code is still needed. My old approach had an own function to detect macros but my new approach uses this part of the code.

Copy link
Collaborator

@mfn mfn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, IMHO this looks great \o/

@barryvdh IMHO we're good to merge here!

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