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

Adding a function that grabs the ID from the request #4591

Merged
merged 1 commit into from Oct 9, 2017
Merged

Adding a function that grabs the ID from the request #4591

merged 1 commit into from Oct 9, 2017

Conversation

catharsisjelly
Copy link
Contributor

@catharsisjelly catharsisjelly commented Aug 10, 2017

Subject

Added a RouteIdHandlerInterface component that will allow developers to change how the ID is taken from the route in the request. By default, it will take the ID from the ID parameter. But the intention is to be able to easily add a component that will decode any encoded IDs. For example using something like HashIds to secure routes from users.

Changelog

### Added
- RouteIdHandler that decides how to process the ID in the route on CRUDController

@catharsisjelly catharsisjelly changed the base branch from 3.x to 2.x August 10, 2017 10:56
@catharsisjelly catharsisjelly changed the base branch from 2.x to 3.x August 10, 2017 10:59
@@ -157,7 +157,7 @@ public function batchActionDelete(ProxyQueryInterface $query)
public function deleteAction($id)
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 wanted to suggest actually deleting the parameter in the action function as it is not used and a bit misleading

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'll open a separate issue for this so it is at least logged

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See #3970

@jlamur
Copy link
Contributor

jlamur commented Aug 10, 2017

Hey @catharsisjelly, thank you for contributing to Sonata!

I'm targeting 3.x as it is the main branch I use, when I tried to switch it to 2.x the PR became huge and I got scared.

It's normal since 2.x is not maintained anymore. The purpose of this sentence in the PR template is to make sure you target master if your changes are not BC, and 3.x if they are. 2.x is never targeted.


About the PR itself, I think it would be better to migrate this function (CRUDController::getObjectIDFromRequest(...)) into the AbstractAdmin or even better IMO, you could create a new component (for example something like RouteIdHandler). Let other contributors decide what's best.

Anyway, I'm almost sure that simply creating a new function into the controller won't be accepted.

@catharsisjelly
Copy link
Contributor Author

@jlamur No problem, thanks for taking a look and the feedback. I was looking for a quick solution to a situation that came up when using Sonata so hence the quick PR. I agree this could be farmed out to a service that does a very specific job possibly even resolving the object so I'll suggest it could be called ObjectResolver or ObjectIDResolver into the mix. I'll be happy to do this and then pull in the service via the container. Will wait for guidance from other Sonata peeps before changing though.

*
* @return array
*/
protected function getObjectIDFromRequest(Request $request)
Copy link
Member

Choose a reason for hiding this comment

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

final?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why do you think this should be final? If I make this final then I can't override it which would defeat the reason I made it in the first place.

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, didn't read the full PR body 😅

*
* @return array
*/
protected function getObjectIDFromRequest(Request $request)
Copy link
Member

Choose a reason for hiding this comment

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

-getObjectIDFromRequest
+getObjectIdFromRequest

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@OskarStark
Copy link
Member

any news here @catharsisjelly ?

@catharsisjelly
Copy link
Contributor Author

@OskarStark Sorry I missed the last bit of feedback but have updated the function name, is there anything else that needs changing/adding?

@jlamur
Copy link
Contributor

jlamur commented Aug 18, 2017

@OskarStark Do you have any opinion on what I wrote before?

@OskarStark
Copy link
Member

I like the idea of the RouteIdHandler, it could be very powerful, what do you think @core23 @greg0ire ?

@greg0ire
Copy link
Contributor

Not adding anything to the AbstractAdmin is best, a new component would indeed be great. You would solve your issue by implementing the interface of this component as you see fit.

@catharsisjelly
Copy link
Contributor Author

@jlamur @OskarStark @greg0ire I'll move this out to a RouteIdHandler service over the weekend if I find the time, thanks for the feedback

@catharsisjelly
Copy link
Contributor Author

I've added the handle, was not sure where to put it so any advice on where you might want it. Test has been written, let me know if there is a better place to put it or you want to implement this differently.

{
return $request->get($admin->getIdParameter());
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Please configure your IDE to always add a newline at end of file, this will make the red pictogram disappear.

Copy link
Contributor

Choose a reason for hiding this comment

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

Same for the test file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done and done, see next push

use Sonata\AdminBundle\Admin\AdminInterface;
use Symfony\Component\HttpFoundation\Request;

class RouteIdHandler
Copy link
Contributor

Choose a reason for hiding this comment

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

Should be final and implement an interface

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You want me to just make a RouteIdHandlerInterface or something more generic?

Copy link
Contributor

@greg0ire greg0ire Aug 18, 2017

Choose a reason for hiding this comment

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

I'd like to see your implementation, with the hash decoding, it will help understand what the purpose of this is, and maybe a better name.

@greg0ire
Copy link
Contributor

Can you show the override with the hash decoding so we better understand the issue?

@@ -27,6 +27,7 @@
<service id="sonata.admin.breadcrumbs_builder" class="Sonata\AdminBundle\Admin\BreadcrumbsBuilder">
<argument>%sonata.admin.configuration.breadcrumbs%</argument>
</service>
<service id="sonata.admin.route_id_handler" class="Sonata\AdminBundle\Route\RouteIdHandler"/>
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be renamed to sonata.admin.default_route_id_handler. sonata.admin.route_id_handler should be an alias you would use for your custom implementation.

Copy link
Contributor

Choose a reason for hiding this comment

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

This means that you would use it for every admin.

@jlamur
Copy link
Contributor

jlamur commented Aug 18, 2017

A short cookbook entry about it would be great! Required or not @greg0ire?

@jlamur
Copy link
Contributor

jlamur commented Aug 18, 2017

What I had in mind was RouteIdHandlerInterface::getIdFromRequest(Request $request) and RouteIdHandlerInterface::getIdFromSubject($subject). Also the service would have been added to the admin like for example the ModelManager, and could be overriden for each admin or globally.

And then the Admin would have used the RouteIdHandlerInterface service to generate urls.

@catharsisjelly
Copy link
Contributor Author

@jlamur thank you that really helps clarify how it would be preferred to be done. I'm going home now but I'll make those changes as soon as I can.

@greg0ire
Copy link
Contributor

@jlamur this makes the admin class grow though. The goal in the future is to split it into components, that it would still know about first, but that we would make independent after that. Let's think hard about how we can avoid editing AbstractAdmin.php at all.

@greg0ire
Copy link
Contributor

Related : #2286 #4440

@greg0ire
Copy link
Contributor

I think maybe the override by admin is not needed at first, what do you think?

Securing route id's with HashId
===============================

If you're working on an app where you need to hide the ID's from the routes then a good way to do ikt would be to use
Copy link
Contributor

@greg0ire greg0ire Aug 18, 2017

Choose a reason for hiding this comment

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

  • "ikt" => "it"
  • "ID's" => "IDs"

return $hashId->decodeHex($request->get($admin->getIdParameter()));
}
}
```
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I've never written RST docs before, I will check the standard and work on the cookbook doc first so it will help understand the change that is needed.

@greg0ire
Copy link
Contributor

The less you override, the better

@jlamur
Copy link
Contributor

jlamur commented Sep 25, 2017

@greg0ire You argued to not do it because it would make the admin class grow.

@greg0ire
Copy link
Contributor

@jlamur is there no way to have the controller figure out things by giving it an admin and a route id handler? It could ask the latter to provide an encoded id, then call AbstractAdmin::generateUrl itself? But not calling generateObjectUrl would probably be a BC-break since that method is overriden, which means we should do that iff the route id handler is not the default one... ugly.

@greg0ire
Copy link
Contributor

@greg0ire did you mean "outside the admin"?

No, I really did mean outside the controller. Anything not dealing directly with HTTP should be outside the controller.

@catharsisjelly
Copy link
Contributor Author

catharsisjelly commented Sep 25, 2017

My idea was this, to change generateObjectUrl to always use the handler so something like

public function generateObjectUrl($name, $object, array $parameters = [], $absolute = UrlGeneratorInterface::ABSOLUTE_PATH)
{
    $parameters['id'] = $this->container->get('sonata.admin.route_id_handler')->encode($this->getUrlsafeIdentifier($object));

    return $this->generateUrl($name, $parameters, $absolute);
}

By the looks of it I can get the container in AbstractAdmin by $this->getConfigurationPool()->getContainer()

That's a little convoluted perhaps but before I go change it all I wanted to just check we all have the same idea

@greg0ire
Copy link
Contributor

greg0ire commented Sep 25, 2017

@catharsisjelly I think it would be better to not touch the admin class, and avoid coupling it even more with the sf container, which looks like a mistake to me.

IMO we should merge this as is, and ultimately move all the route generation outside the admin class, in a service implementing just https://github.com/sonata-project/SonataAdminBundle/blob/3.x/Admin/UrlGeneratorInterface.php . But this is too much to ask you IMO

@SonataCI
Copy link
Collaborator

SonataCI commented Oct 8, 2017

Could you please rebase your PR and fix merge conflicts?

@SonataCI
Copy link
Collaborator

SonataCI commented Oct 8, 2017

Could you please rebase your PR and fix merge conflicts?

@catharsisjelly
Copy link
Contributor Author

I seem to of royally foobar'ed the branch, I have another copy of it in the office. I'll force push that and rebase again on Monday.. DOH!

@greg0ire
Copy link
Contributor

greg0ire commented Oct 8, 2017

Otherwise, use git reflog and reset to a pre fuck-up state then force push

Changed functions that get the ID from Request in CRUDController to use
this new service so that it can be replaced should the developer want to
encode the Ids in their application for security measures
@catharsisjelly
Copy link
Contributor Author

Branch no longer foobared.. Hurrah!

@greg0ire
Copy link
Contributor

greg0ire commented Oct 9, 2017

@core23 please review again

@greg0ire greg0ire merged commit 59ade03 into sonata-project:3.x Oct 9, 2017
@greg0ire
Copy link
Contributor

greg0ire commented Oct 9, 2017

Congrats @catharsisjelly !

@wingsergey
Copy link

After composer update with this release I got [Symfony\Component\DependencyInjection\Exception\RuntimeException] Unable to resolve service "AppBundle\Admin\XxxAdmin": method "setRouteIdHandler()" does not exist.
On v3.23.0 all is ok.

Please investigate

@jlamur
Copy link
Contributor

jlamur commented Oct 12, 2017

@wingsergey Please open a new issue with the full stack trace and bundle versions (or branch in this case, because this PR is not in any release).

@catharsisjelly
Copy link
Contributor Author

@wingsergey I'm not seeing this, when you open the ticket can you reference this PR so I can take a look

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

10 participants