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

[9.x] Chained forwarding #4

Merged
merged 131 commits into from
Jul 8, 2022
Merged

[9.x] Chained forwarding #4

merged 131 commits into from
Jul 8, 2022

Conversation

michael-rubel
Copy link
Owner

@michael-rubel michael-rubel commented Jul 5, 2022

About

This PR introduces a new version of LEC package with code niceties and new features.

Instead of relying on the naming conventions, we can now explicitly define the classes we want to forward, and much to say, we can now chain it. 🔥

How it works?

We can enable the forwarding and define which class to assign in case of missing methods or properties in the base class.

Define the forwarding:

Forwarding::enable()
    ->from(UserService::class)
    ->to(UserRepository::class)
    ->from(UserRepository::class)
    ->to(UserModel::class);

Make a proxy:

$proxy = call(UserService::class);

Call an existing method:

$proxy->existingMethod();

// Returns result from the `UserService::class`

Call a non-existing method:

$proxy->nonExistingMethod();

// Returns result from the `UserRepository::class`, because of forwarding defined above.

Call a non-existing method, but that doesn't exist also in UserRepository::class:

$proxy->nonExistingInRepositoryMethod();

// Returns result from the `UserModel::class`, because of chained forwarding.

So, why?

  • In the first call, we received the result from UserService, because the method exists and it is expected.
  • In the next call, the proxy managed to replace the internal call instance with UserRepository, because of the forwarding defined before.
  • In the final call, the proxy swapped the internal instance to UserModel, because the method also missing in UserRepository (previous instance).

Use cases?

Still, I'm too lazy to think where to put a query. I may do that in the model, but then move it to the service if additional logic arrives. Then all calls stay untouched. I can manage forwardings at any time and without relying on naming conventions. Separation of concerns matters. 🙂

Caveats

Always take attention to which call instance you are working currently when calling methods, accessing, or assigning properties. If some of them don't exist, the proxy will swap an instance and you'll lose the internal state. I'm thinking about storing a previous instance or warning a developer in such a case, we'll see if it fits reality.

@michael-rubel
Copy link
Owner Author

michael-rubel commented Jul 6, 2022

Property assignment forwarding is removed, cause it doesn't make much sense to forward that. If you need to perform a property assignment, just create a new instance of CallProxy. If you'll try to interact with the same property after a state swap, the exception will be thrown to avoid working on an unexpected instance which I believe improves the developer experience.

Forwarding::enable()
    ->from(UserService::class)
    ->to(UserRepository::class);

$proxy = call(UserService::class);

$proxy->property = true; // `UserService::class`
$proxy->property; // Returns `true`

$proxy->methodMissingInServiceButExistInRepository(); // `UserRepository::class`.
$proxy->property; // `InstanceInteractionException` is thrown.

@michael-rubel michael-rubel marked this pull request as ready for review July 7, 2022 08:30
@michael-rubel michael-rubel merged commit cddacdb into main Jul 8, 2022
@michael-rubel michael-rubel deleted the wip/version-9 branch July 8, 2022 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants