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

Deprecate some AbstractAdmin methods #6885

Merged
merged 6 commits into from
Mar 13, 2021

Conversation

VincentLanglet
Copy link
Member

@VincentLanglet VincentLanglet commented Feb 21, 2021

Subject

I am targeting this branch, because BC

Changelog

### Deprecated
- `AbstractAdmin::buildForm()`
- `AbstractAdmin::buildDatagrid()`
- `AbstractAdmin::buildShow()`
- `AbstractAdmin::buildList()`
- `AbstractAdmin::canAccessObject()` in favor of `AbstractAdmin::hasAccess()`
- `AdminInterface::canAccessObject()`
- `AdminInterface::configureActionButtons()` and `AbstractAdmin::configureActionButtons()` will become protected

@VincentLanglet VincentLanglet marked this pull request as ready for review February 22, 2021 08:48
@VincentLanglet VincentLanglet requested a review from a team February 22, 2021 08:48
@VincentLanglet VincentLanglet added this to the 4.0 milestone Feb 22, 2021
phansys
phansys previously approved these changes Feb 22, 2021
@VincentLanglet VincentLanglet requested a review from a team February 22, 2021 21:25
@franmomu franmomu added the minor label Feb 22, 2021
@@ -2690,7 +2716,9 @@ public function configureActionButtons($action, $object = null)

if (\in_array($action, ['show', 'delete', 'acl', 'history'], true)
&& $this->hasRoute('edit')
&& $this->canAccessObject('edit', $object)
Copy link
Member

@franmomu franmomu Feb 22, 2021

Choose a reason for hiding this comment

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

Do we have to remove this one?

IMO looks better to use a method to check this rather than substitute this call with null !== $object && $this->hasAccess('x', $object) everywhere.

There is also this check inside the canAccessObject method: if (!$this->id($object)) { }, that I don't know if can be removed.

EDIT: Looking at the calls, I think we can even add in that method a check for $this->hasRoute('route') to make those if smaller.

Copy link
Member Author

Choose a reason for hiding this comment

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

  • There is a lot of methods in the AdminInterface. I don't think we should exposing two methods with almost the same behavior.
  • We're mixing the access notion in both the AccessRegistryInterface and the AdminInterface
  • Both can be called with an object (hasAccess('edit', $object) and canAccessObject('edit', $object)). How to know which one I should use ? If you look at the code, sometimes we were using one, sometimes the second one, this is really confusing.

Maybe deprecating this method is not the right thing to do.

  • Changing AccessRegistryInterface::hasAccess($action, $object) to AccessRegistryInterface::hasAccess($action) ? This way it's clear, if you're concerned about the action access, use hasAccess ; if you're concerned about the object, use canAccessObject.
  • Renaming the canAccessObject method ?

And we could also move the canAccessObject method to the AccessRegistryInterface.

Copy link
Member Author

Choose a reason for hiding this comment

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

I take a new look at the code.

Firstly, the check $this->id($object) is needed.

Secondly, when you look at the following code

{% if admin.canAccessObject('edit', object)
    and admin.hasRoute('edit')
%}
    <li>
        <a class="sonata-action-element" href="{{ admin.generateObjectUrl('edit', object) }}">
            <i class="fa fa-edit" aria-hidden="true"></i>
            {{ 'link_action_edit'|trans({}, 'SonataAdminBundle') }}
        </a>
    </li>
{% endif %}

Nothing can guarantee that

  • the object is not null. User could have a different implementation of canAccessObject, and then generateObjectUrl will give a TypeError.
  • canAccessObject and generateObjectUrl are related. There are in different interfaces.

So I still think it's better to deprecate canAccessObject and using explicit checks.

Copy link
Member

Choose a reason for hiding this comment

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

To be honest I don't understand the reasoning behind removing a meaningful method name in favor of explicit checks:

if ($this->hasRoute('acl')
    && null !== $object
    && null !== $this->id($object)
    && $this->hasAccess('acl', $object)
)

vs:

if ($this->canAccessObject('acl', object))

Every time there is a call to canAccessObject, there is also a hasRoute call, so I guess that method (don't know if canAccessObject or other) could also check that.

IMHO (for the sake of maintainability) it is better to have a method as a concept that the developer can understand when looking at it rather than several checks.

the object is not null. User could have a different implementation of canAccessObject, and then generateObjectUrl will give a TypeError.

I think this is different, in this case if there is a call to generateObjectUrl that needs an object, makes sense to check if that exists.

Copy link
Member Author

Choose a reason for hiding this comment

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

To be honest I don't understand the reasoning behind removing a meaningful method name in favor of explicit checks:

if ($this->hasRoute('acl')
    && null !== $object
    && null !== $this->id($object)
    && $this->hasAccess('acl', $object)
)

vs:

if ($this->canAccessObject('acl', object))

You're not always calling $this->canAccessObject, you're often calling $admin->canAccessObject, so you're calling this in the AdminInterface, not the AbstractAdmin. You don't know how the developer will implement this method.

I should be allowed to have this implementation:

public function canAccessObject($action,  $object) {
   return true;
}

Does the SonataAdmin code still works with this implementation ? No. We rely on a specific implementation. So this method shouldn't be in the interface. It could be in a service, but since we're not using it a lot, using specific checks seems enough to me.

Every time there is a call to canAccessObject, there is also a hasRoute call, so I guess that method (don't know if canAccessObject or other) could also check that.
IMHO (for the sake of maintainability) it is better to have a method as a concept that the developer can understand when looking at it rather than several checks.

Still, If you do this, you'll rely on a specific implementation of canAccessObject which is against the purpose of an interface.
If a method should exist, it would be canGenerateObjectUrl and be in the UrlGeneratorInterface.

the object is not null. User could have a different implementation of canAccessObject, and then generateObjectUrl will give a TypeError.

I think this is different, in this case if there is a call to generateObjectUrl that needs an object, makes sense to check if that exists.

With the implementation I gave you, the twig template is giving a TypeError.

Copy link
Member

Choose a reason for hiding this comment

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

the object is not null. User could have a different implementation of canAccessObject, and then generateObjectUrl will give a TypeError.

I think this is different, in this case if there is a call to generateObjectUrl that needs an object, makes sense to check if that exists.

With the implementation I gave you, the twig template is giving a TypeError.

This is precisely what I meant with my previous comment, in case we need to check that object is not null (because there is call that needs that object), make sense to add that extra check (admin.whatever and object != null).

Copy link
Member Author

Choose a reason for hiding this comment

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

I misunderstood that part. But the rest of my message is still valid.
We're relying on the implementation of canAccessObject when it's not even in the same interface.

For a list, we're doing hasRoute and hasAccess.
If for a show, you're doing hasRoute and canAccessObject or worst, just doing canAccessObject it won't be consistent with the list, it could lead to weird behavior if I override the canAccessObject method.

That's why I think it's better to keep the checks we need instead of hiding them inside a method which is in the public API. Given that fact, only the $this->id($object) !== null is useful to keep inside this method. Does it worth a method ? I'm not sure about this.

If you look more at it, you can even see that the $this->id($object) !== null check is wrong. Since generateObjectUrl is relying on getUrlSafeIdentifier.

If we want to keep abstraction, the only method to provide would be

public function canGenerateObjectUrl(object $object) {
    return nul !== $this->getUrlSafeIdentifier($object);
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Friendly ping @franmomu @sonata-project/contributors WDYT ?

@VincentLanglet VincentLanglet marked this pull request as draft February 23, 2021 01:43
@phansys phansys marked this pull request as ready for review February 23, 2021 14:48
@phansys phansys marked this pull request as draft February 23, 2021 14:48
@VincentLanglet VincentLanglet marked this pull request as ready for review February 23, 2021 19:57
@VincentLanglet VincentLanglet requested review from franmomu, phansys and a team February 23, 2021 19:57
@core23
Copy link
Member

core23 commented Feb 27, 2021

Are there any replacements for this methods?

@VincentLanglet
Copy link
Member Author

Are there any replacements for this methods?

build* methods are going to be private. They are not meant to be called by the developer.
AbstractAdmin::configureActionButtons is going to be protected, so it's removed from the interface. There is already getActionButtons.

@core23
Copy link
Member

core23 commented Feb 27, 2021

Are there any replacements for this methods?

build* methods are going to be private. They are not meant to be called by the developer.
AbstractAdmin::configureActionButtons is going to be protected, so it's removed from the interface. There is already getActionButtons.

This information should be added to the CHANGELOG.

@VincentLanglet
Copy link
Member Author

The changelog should be better now.

OskarStark
OskarStark previously approved these changes Mar 7, 2021
@SonataCI
Copy link
Collaborator

Could you please rebase your PR and fix merge conflicts?

dmaicher
dmaicher previously approved these changes Mar 12, 2021
Copy link
Contributor

@dmaicher dmaicher left a comment

Choose a reason for hiding this comment

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

LGTM.

I also had a look and from what I can tell it does not impact any of my projects where I'm using SonataAdminBundle.

@dmaicher
Copy link
Contributor

@franmomu @core23 could you also have another look? 😊

dmaicher
dmaicher previously approved these changes Mar 12, 2021
Copy link
Member

@phansys phansys left a comment

Choose a reason for hiding this comment

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

GitHub is responding with 502.
At src/Admin/AbstractAdmin.php:2914:

                .' and will be removed an in 4.0. Use `hasAccess()` instead.',

@@ -3179,10 +3243,18 @@ protected function buildList()
}

/**
* Build the form FieldDescription collection.
* NEXT_MAJOR: Change visibility to private.
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we add a @deprecated annotation, just in case the users are overriding this method without calling parent?

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

Copy link
Member

Choose a reason for hiding this comment

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

What about buildShow()?

Copy link
Member

@phansys phansys left a comment

Choose a reason for hiding this comment

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

IMO, the chengelog must explicitly tell which deprecated methods will reduce its visibility.

@VincentLanglet
Copy link
Member Author

IMO, the chengelog must explicitly tell which deprecated methods will reduce its visibility.

If it's private, it's the same no ?

@phansys
Copy link
Member

phansys commented Mar 12, 2021

If it's private, it's the same no ?

Yes, I mean the cases where we are deprecating a method but not for removal, but for reduced visibility.

@VincentLanglet
Copy link
Member Author

I did:

AdminInterface::configureActionButtons() and AbstractAdmin::configureActionButtons() will become protected

@phansys
Copy link
Member

phansys commented Mar 12, 2021

These methods will reduce its visibility from public/protected to private, but the changelog just states that they are deprecated:

  • AbstractAdmin::buildDatagrid()
  • AbstractAdmin::buildShow()
  • AbstractAdmin::buildList()
  • AbstractAdmin::buildForm()

That's what I mean.

@VincentLanglet
Copy link
Member Author

These methods will reduce its visibility from public/protected to private, but the changelog just states that they are deprecated:

  • AbstractAdmin::buildDatagrid()
  • AbstractAdmin::buildShow()
  • AbstractAdmin::buildList()
  • AbstractAdmin::buildForm()

That's what I mean.

But since private and removed have the same impact for the developer, I don't think we should be more precise.
The developer won't be able to use it, that's all. He shouldn't know about our implementation.
I could rename buildDatagrid() to a private method with another name and stop using a private method.

@phansys
Copy link
Member

phansys commented Mar 12, 2021

He shouldn't know about our implementation.

I agree with this fact. Dismiss my suggestion.

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

Successfully merging this pull request may close these issues.

None yet

7 participants