Skip to content

Conversation

@goetas
Copy link

@goetas goetas commented Sep 6, 2019

Hi, I have created this PR with the code changes I was suggesting.
Going to comment in the code the main changes

@goetas goetas force-pushed the feature/extract-rate-limit-manager branch from f30fd09 to dddd936 Compare September 6, 2019 14:45
Copy link
Author

@goetas goetas left a comment

Choose a reason for hiding this comment

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

I have highlighted the main changes, did not update the tests yet, if you are ok with it I can do that too.

* @param EventDispatcherInterface $eventDispatcher
* @param RateLimitService $rateLimitService
* @param PathLimitProcessor $pathLimitProcessor
* @param LimitProcessorInterface $limitProcessor
Copy link
Author

Choose a reason for hiding this comment

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

This class now depends only on the interface, not on implementations anymore

return;
}

// Find the best match
Copy link
Author

Choose a reason for hiding this comment

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

this logic has been moved in the AnnotationLimitProcessor as it is the one responsible for annotations

use Noxlogic\RateLimitBundle\LimitProcessorInterface;
use Symfony\Component\HttpFoundation\Request;

class AnnotationLimitProcessor implements LimitProcessorInterface
Copy link
Author

Choose a reason for hiding this comment

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

This class is a service now, it is instantiated only once by the symfony DI. If the annotations package is not available, disabling it will not require changes in the code, only changing the noxlogic_rate_limit.processor alias

Copy link
Owner

Choose a reason for hiding this comment

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

Main reason to move it into the service - to create object only once via DI?

Disabling class in DI good approach. Maybe I wrong, but it doesn't bring big value, cause if annotation package is not available we need to disable rate_limit_annotation_listener. And without events usage, annotation class will not be used as well.

Before that changes, Util/AnnotationLimitProcessor.php were tightly coupled with symfony framework, cause its use symfony related attributes.

So in general, I agree, that it can be service class, cause in any case it right now symfony specific.

Copy link
Author

Choose a reason for hiding this comment

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

Having stateless services is always a good idea, in the previous implementation AnnotationLimitProcessor had to be instantiated in the request process, while now is instantiated via DI (with all the possible optimizations that symfony will be able to do as the upcoming preloading in 7.4).

Did not know that the aim of this bundle is to be framework agnostic.Wiring it into laravel might be possible, but not sure is the main goal.

* @return string
*/
public function getRateLimitAlias(Request $request);
public function getRateLimitAlias(Request $request, callable $controller);
Copy link
Author

Choose a reason for hiding this comment

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

only thing that I did not manager to solve in an elegant way is the $controller callable

Copy link
Owner

Choose a reason for hiding this comment

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

Will think about that case.
Cause original intention were to make Rate Limit framework agnostic.
With controller argument we are in situation, when interface is dictated by DI and symfony logic, that request and current controller can differ.

private $controller;

public function __construct(array $annotations, callable $controller)
public function __construct(LimitProcessorInterface $fallback)
Copy link
Author

Choose a reason for hiding this comment

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

Here using the chain of responsibility pattern

Copy link
Owner

@amanto amanto left a comment

Choose a reason for hiding this comment

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

@goetas added some ideas. Will think about common interface.

* @return string
*/
public function getRateLimitAlias(Request $request);
public function getRateLimitAlias(Request $request, callable $controller);
Copy link
Owner

Choose a reason for hiding this comment

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

Will think about that case.
Cause original intention were to make Rate Limit framework agnostic.
With controller argument we are in situation, when interface is dictated by DI and symfony logic, that request and current controller can differ.

use Noxlogic\RateLimitBundle\LimitProcessorInterface;
use Symfony\Component\HttpFoundation\Request;

class AnnotationLimitProcessor implements LimitProcessorInterface
Copy link
Owner

Choose a reason for hiding this comment

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

Main reason to move it into the service - to create object only once via DI?

Disabling class in DI good approach. Maybe I wrong, but it doesn't bring big value, cause if annotation package is not available we need to disable rate_limit_annotation_listener. And without events usage, annotation class will not be used as well.

Before that changes, Util/AnnotationLimitProcessor.php were tightly coupled with symfony framework, cause its use symfony related attributes.

So in general, I agree, that it can be service class, cause in any case it right now symfony specific.

public function getRateLimitAlias(Request $request)
public function getRateLimitAlias(Request $request, callable $controller)
{
$annotations = $request->attributes->get('_x-rate-limit', array());
Copy link
Owner

Choose a reason for hiding this comment

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

We are repeating this part in each of method.
I think, that its related to the fact, that current implementation with events implies very dynamic way to work with annotations. From my point of view, that fact push do not use service or need to rebuild service each time as new object.

Best option as I see - to load all annotation ahead, so we can really use fallback logic with chain of responsibility. Not sure if its possible in symfony, will try to find out. One worry, that it can be breacking change.

Copy link
Author

Choose a reason for hiding this comment

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

Instantiating a new object is more expensive in therms of CPU than calling a method (but I think is too soon to consider this kind of optimizations).

Currently symfony does not allow to have dependency-injection containers per url/path, so this kind of if checks are inevitable. The same if was done here in the previous implementation.

But then based on that if condition was changing the underlying services, by swapping the rate limit processor with AnnotationLimitProcessor... that to me sounds a dirty trick. While the proposed implementation used the well known chain-of-responsibility pattern.

}

public function getRateLimitAlias(Request $request)
public function getRateLimitAlias(Request $request, callable $controller)
Copy link
Owner

Choose a reason for hiding this comment

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

Can't we use $request->attributes->get('_controller') as $controller ?

Copy link
Author

Choose a reason for hiding this comment

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

That's definitely an option! That would be great

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.

2 participants