- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 329
Case of self-referencing fixtures #502
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
Comments
I don't think we can drop support for it altogether - that would be taking a pretty aggressive stance on what we feel is an acceptable object structure. So, given that, we can either come up with a new syntax / suggested approach for dealing with it (something like a second-pass reconciliation step) or we can engineer to make it work. I lean towards making it work in the cases it has been working, and throwing up a flag in the cases you've recognized where it won't work. Personally, I feel like your description of generating all the fixtures and ordering their build steps intelligently is the right move - it's easy to imagine in the future wanting to be able to manipulate the order for any number of reasons (process, performance, etc.). Additionally, this would lay groundwork for allowing customization at the user level, if it ever went there. Given the engineering of the library at this point, this doesn't seem over-engineered to me. I think we can save the "skip and retry" step for a later milestone - it's a useful feature, but we're talking about edge cases at that point. So, to reiterate, I would suggest:
One thing you also might consider is changing the population portion to support lambda population - basically, rather than passing an instance of the reference, you pass a function that returns an instance of the object. Hidden behind that function can be a simple random item in a list, or a process that builds a not-yet-handled object. This strikes me as a reliable approach, but is definitely more conceptually "stressful". |
After sleeping on it, it's clear that this is the way that makes more sense. There is only one scenario I can think of where it would fail, it would be the one where an entity has a clone in a setter. I have no easy way to detect that, but I think it is fair to not expect alice to handle this case. Maybe in the future, we can add a flag to specify that entity X should be generated in one go to avoid this situation, i.e. let the user solve this issue on a case by case basis, as it has strong limitations and would break things for too many people to be switched on as the default. That said I must say I was surprised that: Dummy:
dummy0:
relatedDummy: '@dummy*' works. Thinking about it, this is perfectly valid, but it was a scenario I did not account for and that confused me. |
Instead of trying to generate each fixture one by one in one go, the process is done in two passes. During the first pass, the objects are simply instantiated. During the second pass, they are hydrated and the method calls are made. Closes nelmio#502
Instead of trying to generate each fixture one by one in one go, the process is done in two passes. During the first pass, the objects are simply instantiated. During the second pass, they are hydrated and the method calls are made. Closes nelmio#502
Instead of trying to generate each fixture one by one in one go, the process is done in two passes. During the first pass, the objects are simply instantiated. During the second pass, they are hydrated and the method calls are made. Closes #502
Example:
This, in 2.x, will somehow works. Because in 2.x, all the fixtures are first instantiated and then populated, so
@dummy*
will always find a match. There is however two problems with that:relatedDummy
is no longer set via a setter but in the constructor, this will fail as no instance matching@dummy*
will be found:Dummy
is there is immutability involved somewhere this will break. Examples:Or maybe a more practical example (the one above is really a bit weird):
If
ImmutableDummy
is really immutable then any modification on it (for example in the optional method calls step cf. #388), any modification made on the instance won't affect the injected instances.This problem is in 2.x but I'm facing the same in 3.x. I changed the strategy in 3.x to generate (instantiate + populate + do optional calls) on an instance basis. This allows to make use of recursion and basically allow to make the loading of the fixtures independent of the order in which the fixtures have been declared to solve issues such as #257. But then that means I'm encountering the same issue as in the second example (dummies injected in the constructor) for:
A solution I see is instead of going through all the fixtures randomly, try to play it smart: generate the fixtures without a population step first (makes sure all immutable structure are instantiated, as immutable objects won't have this "population" step). Then try to instantiate all fixtures without any constructor (this makes sure they won't be injected an incomplete object which we will have no means to fix after). Try to populate those objects and then generate one by one the fixtures left. A safety could be added to make so that if generating a fixture fails, we skip it and retry it later.
But honestly this is quite a heavy-engineered solution and I'm not sure it's worth it. Sure it will break a few things, some people won't be happy, but it's weird case that already don't work in all cases and creates more problem than anything else.
@tshelburne WDYT? I must admit I'm a bit upset with this issue as the time of writing so don't mind me if I'm a bit negative. But I'm curious if you have an alternative solution in mind or if you're ok to drop it for 3.x.
The text was updated successfully, but these errors were encountered: