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 support for protected Attribute accessors #1339

Merged
merged 12 commits into from
Feb 20, 2023

Conversation

pindab0ter
Copy link
Contributor

@pindab0ter pindab0ter commented Apr 6, 2022

Summary

The documentation for defining accessors states that “To define an accessor, create a protected method on your model to represent the accessible attribute.” (emphasis mine).

This is currently not supported by IDE Helper as noted in #1293.

The problem is that get_class_methods doesn't return protected or private functions. The solution is to use Reflection instead and filter out any unwanted methods:

  • Methods marked as private since marking an accessor as private breaks the accessor and the two methods defined in
  • Two methods defined in each model through the \Illuminate\Database\Eloquent\Concerns\HasAttributes trait.

Any accessors marked as private will now not show up in the IDE Helper files. I chose to not mark this as a breaking change since those accessors would not have worked anyway.

This PR conflicts with #1338.

Type of change

  • New feature (non-breaking change which adds functionality)

Checklist

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

@pindab0ter pindab0ter force-pushed the feature/protected-accessor branch 2 times, most recently from f2e0c6d to 4273911 Compare April 6, 2022 10:38
@pindab0ter pindab0ter marked this pull request as ready for review April 6, 2022 10:38
@@ -1096,6 +1096,9 @@ protected function hasCamelCaseModelProperties()

protected function getAttributeReturnType(Model $model, \ReflectionMethod $reflectionMethod): Collection
{
// Private/protected ReflectionMethods require setAccessible prior to PHP 8.1
$reflectionMethod->setAccessible(true);
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 chose not to wrap this in an if-statement checking for PHP_VERSION_ID since according to the docs from PHP 8.1 onward this method call is a noop.

@pindab0ter
Copy link
Contributor Author

Can this PR be looked at? Using protected rather than public is the documented way of using this functionality and prevents accidentally calling the method instead of the magic property.

da-mask

This comment was marked as duplicate.

Copy link

@da-mask da-mask left a comment

Choose a reason for hiding this comment

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

Looks good to me, but I'm a nobody.

@mfn
Copy link
Collaborator

mfn commented May 4, 2022

Will soon check it out; this competes with #1325 right?

@pindab0ter
Copy link
Contributor Author

Will soon check it out; this competes with #1325 right?

Correct.

@pindab0ter
Copy link
Contributor Author

I would like to ask if someone could look into this again. The summary states the case/necessity for this PR.

There are some fairly major changes to ModelsCommand.php, but all tests are green. They also result in that flow being more consistent: Everything now uses ReflectionClass/ReflectionMethod instead of only the parts that explicitly require that.

Copy link

@danieleambrosino danieleambrosino left a comment

Choose a reason for hiding this comment

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

Looks perfectly fine to me, hope this will get reviewed and merged by a maintainer soon.
Very good job @pindab0ter!

@pindab0ter
Copy link
Contributor Author

I would like to update this PR, but it relies on #1338. I would like to note that this PR is required to support the Attribute accessors that are new since Laravel 9. Without this PR, they are not recognised when following Laravel's documentation in implementing those.

@matiaslauriti
Copy link

matiaslauriti commented Aug 19, 2022

I am currently using Attribute in some places and it is making me very mad. I truly don't want to make the methods public, because that is not how the framework works and just changing them to public because we still don't have this fix merged (reported a long time ago) makes me really mad, as if anyone runs the command, we will lose those properties unless they are aware of this "bug" and they change the properties to public, run the command, and move them back to protected...

That would be unmaintainable... so please, @mfn @barryvdh or any collaborator, member or admin, can this be looked at and merged ASAP?

@pindab0ter I do see there are conflicts (but I can't see them), could you fix them so this can be taken care of immediately?

Would appreciate having this merged and release ASAP because it is a must (required-dev) for any Laravel project I work on, so this is truly a gem package for devs, so having this issue not fixed breaks my heart 😥

@pindab0ter
Copy link
Contributor Author

I rebased this PR onto #1338 which is in turn rebased on the most recent commit on main.

Please review #1338 as this PR relies on it. This is not a massive change and all changes are covered by tests. It would mean a lot to a lot of people if this was accepted.

@pindab0ter
Copy link
Contributor Author

@mfn With the 2.13.0 release, do you think it's possible to get this PR done?

I would like to reiterate that this package as of now still does not support a basic Laravel feature introduced in Laravel 9; Attribute accessors.

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, I'm also preferring this over #1325 , covers more cases.

My feedback:

  • please don't change the visibility of existing attributes -> please create a new column/attribute using protected (basically like you added the private to show
  • to improve readability of the PR, I suggest to add $method = $methodReflection->getName(); at the top of the loop -> this will reduce a LOT of noise in the PR (except for the cases where indeed have to pass on the reflect object)
  • resolve the merge conflicts

(ps: any reason for the style changes?)

thanks!

@pindab0ter
Copy link
Contributor Author

pindab0ter commented Feb 18, 2023

  • I changed the visibility of the test methods (I assume this is what you're referring to) because this is what the Laravel Docs on Attributes states; "To define an accessor, create a protected method on your model […]." What reason is there for not wanting to change the visibility to what it should be from now on?
  • I changed variable usage to reduce clutter as much as possible. I would suggest renaming $method to $methodName to prevent possible confusion about the type of the variable once you have OKed this PR, if that's okay with you.
  • I made a few style changes because I felt the code style wasn't in line with the style of the rest of the code in those places. If you disagree, I can revert those changes.

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.

PR is so much more readable now, thank you!

Approving, the error with psalm is unrelated and needs its own fix.

@mfn
Copy link
Collaborator

mfn commented Feb 19, 2023

Approving, the error with psalm is unrelated and needs its own fix.

Btw, reported this over there -> vimeo/psalm#9345

@pindab0ter
Copy link
Contributor Author

Awesome, thanks!

What are your thoughts on this?

I would suggest renaming $method to $methodName to prevent possible confusion about the type of the variable […].

Can you do #1338 next? It adds better support for (missing) type hinting of Attributes.

@barryvdh barryvdh merged commit 3988564 into barryvdh:master Feb 20, 2023
@pindab0ter pindab0ter deleted the feature/protected-accessor branch February 20, 2023 08:45
@mfn mfn mentioned this pull request Jan 28, 2024
9 tasks
d3v2a pushed a commit to d3v2a/laravel-ide-helper that referenced this pull request Feb 16, 2024
* Add support for protected Attribute accessors

* Fix formatting

* Prevent accessors methods marked as private from being added

* Exclude specific accessors based on trait instead of class

* Add changelog entry

* Add clarifying comment

* Fix accessor attributes not working on PHP < 8.1

* Reintroduce method variable to reduce PR clutter

* Change variable name to reduce PR clutter

* Update CHANGELOG.md

---------

Co-authored-by: Barry vd. Heuvel <barry@fruitcake.nl>
Co-authored-by: Barry vd. Heuvel <barryvdh@gmail.com>
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.

6 participants