-
Notifications
You must be signed in to change notification settings - Fork 342
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 support for extensions and PSR-11 #154
Conversation
return new Container($this->container); | ||
} | ||
|
||
public static function getDefault(): ContainerInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static function getDefault(): ContainerInterface | |
public static function create(): ContainerInterface |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be confused with "build".
I want to be clear that this builds the default container.. Maybe this should be part of Generator
or Factory
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not even sure we need this class, to be honest.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want the container to be immutable. Using a builder class is the simplest and easiest to understand.
The alternative would be that the container builds itself and it is immutable only after we run Container::build()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review
src/Faker/Container/Container.php
Outdated
try { | ||
return $this->cache[$id] = new $data(); | ||
} catch (\Throwable $e) { | ||
throw new ContainerException(sprintf('Could not instantiate class "%s"', $id), 0, $e); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the benefit of this change?
Thank you for the review, The PR is updated and build is green. I left you some questions |
src/Faker/English/FileExtension.php
Outdated
|
||
declare(strict_types=1); | ||
|
||
namespace Faker\English; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about the namespace, is an implementation for German going to be different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this. I added it in this namespace to be constant with the German package.
The German package is called fakerphp/german
, it lives in https://github.com/FakerPHP/German and its root namespace would be Faker\German
.
So there will be a Faker\German\PersonDe
and Faker\German\PersonAu
..
However, The Australian English will not be in the root package. There should also be a fakerphp/english
with Brittish, Australian... etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We currently have quite a few providers that are not necessarily language specific (besides this one), such as UserAgent
or Barcode
.
How about adding a dedicated package/namespace that provides those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have considered that and decided not to.
It is impossible of us to know if there is a specific Russian barcode or a Chinese UserAgent. So I think the core should treat all extensions the same. But I agree with you, there are only some that are likely to be localised.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imo English should not be in the core package as well? Lets just put it in its own package.
Meaning people will require then locale extension and not the core directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have considered that and decided not to.
It is impossible of us to know if there is a specific Russian barcode or a Chinese UserAgent. So I think the core should treat all extensions the same. But I agree with you, there are only some that are likely to be localised.
But arent we duplicating a lot this way? There are a lot of generic things so. Medical / Barcore / Number / Date etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. We are not duplicating.
Since the core package includes all English and “generic providers”, no language specific extensions need to duplicate anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm somewhat reminded of our conversation in Nyholm/next-faker#14.
These "generic providers" are in the fakerphp/english
package or in the core? How do we differentiate between generic and "localizable"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why even put english in the core package. I think it is a benefit to keep it separated and just require it. Reason for this is that it is more easy to setup new locale extensions from a proper example repo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Imo English should not be in the core package as well? Lets just put it in its own package.
If so, a third party library will require fakerphp/faker
and get an unusable library because it does not have any extension. So the third partly library will then require fakerphp/faker
and fakerphp/english
and the potential "win" for separating them is lost and we only caused confusion.
But arent we duplicating a lot this way? There are a lot of generic things so. Medical / Barcore / Number / Date etc
No, we are not. The fakerphp/german
does not have to include a Medical extension, it will just keep using the default ones.
These "generic providers" are in the fakerphp/english package or in the core?
They are in the code.
How do we differentiate between generic and "localizable"?
Just for context (so I understand), I have a counter question: Why would you need to differentiate between generic and "localizable"?
Reason for this is that it is more easy to setup new locale extensions from a proper example repo
Im not sure this is true. Feel free to open a new issue discussion the pros and cons. Consider that 90% of the users will only use the english locale and also see the discussions on https://github.com/Nyholm/next-faker
I would also like to remind you about my PR description:
This PR does not mean that it is a perfect solution, but it is a step towards it.
I dont mean to turn down this discussion, but it is quite far from the purpose of this PR.
cb5e45e
to
06c25bb
Compare
src/Faker/Container/Container.php
Outdated
} | ||
|
||
try { | ||
return $this->services[$id] = new $definition(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Writing code this way has the following downsides:
-
a reader does not know whether the intent is to compare or assign a value
return $this->services[$id] == new $definition();
-
it does not separate concerns
- trying to create a value and catching an exception that can be potentially thrown
- assigning a value
- returning a value
-
it also hides whether we have tested both failure and success cases, this line of code will be covered even when we have only a test case for one of failure or success case
Probably best to rebase on top of `main! |
src/Faker/Container/Container.php
Outdated
public function has($id) | ||
{ | ||
if (!is_string($id)) { | ||
throw new \LogicException(sprintf('First argument of %s::get() must be string', self::class)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
throw new \LogicException(sprintf('First argument of %s::get() must be string', self::class)); | |
throw new \InvalidArgumentException(sprintf('First argument of %s::get() must be string', self::class)); |
use Faker\Core\File; | ||
use Faker\Extension\FileExtension; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm..
Faker\Extension\File
is an interface.Faker\English\FileExtension
is the implementation of that interface.I could have named it
Faker\English\File
but that would be more confusing.
It is only confusing when we always import every single class:
diff --git a/src/Faker/Container/ContainerBuilder.php b/src/Faker/Container/ContainerBuilder.php
index b86992b9..109f03ea 100644
--- a/src/Faker/Container/ContainerBuilder.php
+++ b/src/Faker/Container/ContainerBuilder.php
@@ -4,8 +4,8 @@ declare(strict_types=1);
namespace Faker\Container;
-use Faker\Core\File;
-use Faker\Extension\FileExtension;
+use Faker\Core;
+use Faker\Extension;
use Psr\Container\ContainerInterface;
/**
@@ -61,7 +61,7 @@ final class ContainerBuilder
public static function defaultExtensions(): array
{
return [
- FileExtension::class => File::class
+ Extension\File::class => Core\File::class
];
}
Thank you for all the reviews, suggestions and opinions. I think this PR is way better now than a few days ago. |
@localheinz im happy to take this in as is, what is your view? We can always change from there. Like @Nyholm said it is not a 100% perfect solution yet but the foundation of the future. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
We can still reiterate when necessary!
Wohoo. Thank you for merging |
* Adding support for extensions and PSR-11 * Added getDefaultExtensions * minor * Apply suggestions from code review Co-authored-by: Andreas Möller <am@localheinz.com> * CS fixes * Refactor container * CS * Renamed namespace * Updated names and namespaces * Fix: Run 'make cs' * Fix: Remove unnecessary initialization * Fix: Add missing throws annotation * Fix: Run 'make baseline' * Fix: Wrapping * Fix: Throw InvalidArgumentException * Fix: Run 'make cs' * Fix: Use elvis operator * Fix: Move exception to Extension namespace * Fix: Add return type declarations * Fix: Avoid unnecessary imports * Fix: Whitespace * Fix: Add covers annotation * Enhancement: Throw RuntimeException when service can not be resolved to extension * Fix: DocBlock * Fix: Run 'make cs' * Fix: Namespace * Enhancement: Merge Container into Extension namespace * Added dock block * cs Co-authored-by: Andreas Möller <am@localheinz.com>
This is the first steps to move towards what is described in https://github.com/Nyholm/next-faker
All classes/interfaces are marked with "Experimental". This PR does not mean that it is a perfect solution, but it is a step towards it.