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
[Clock] Add Clock
class and now()
function
#48642
Conversation
2a6c3d7
to
9e7bd07
Compare
9e7bd07
to
1cc21b7
Compare
be99e56
to
e2e654f
Compare
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 that hijacked enum is better than a regular class with private+final construct, but it works and made me laugh :)
Less boilerplate FTW (+ newInstanceWithoutConstructor won't allow bypassing ;) ) |
e2e654f
to
73474b7
Compare
Thanks to various comments, I figured out a better API for this global clock.
|
Do not add it to the API, please! I'm begging you! 🙏 It is easy to achieve by simple wrapper when it is really needed. Static calls to some global state can be useful in some code, but most of the time it leads to maintenance problems and bugs. People would use it without reason if that was in the API. The feature looks like Laravels Facades. Every time I've seen them used, they are used wrong. Not because the Facades are something bad, but because developers (especially not very experienced) do bad things with them. Facades are constantly overused/abused just because it is convenient, they are described in guides, and "they all do that, why I shouldn't?" The good answer to how to inject time (and other dependencies) into Doctrines' entities is repository. Repositories are the best place to provide entities, including new ones. If it's difficult in your case or doesn't suit your needs, there are many other options #48564 (comment) But... Please, do not add static calls to the API. |
I plead guilty to having a With this implementation, I don't see how I could override the current time for functional testing. I can redefine the $client = static::createClient();
$crawler = Clock::with($mockClock, fn() => $client->request('GET', '/')); |
@GromNaN you nailed it :) |
73474b7
to
d660ee7
Compare
|
d660ee7
to
4795584
Compare
6ef4125
to
20ca626
Compare
20ca626
to
09acb88
Compare
Clock
class and now()
function
Thanks for the feedback. PR updated. It now provides integration with services + phpunit. PR description updated. |
09acb88
to
ab6b038
Compare
true === $when => new MockClock(), | ||
$when instanceof ClockInterface => $when, | ||
$when instanceof \DateTimeImmutable => new MockClock($when), | ||
default => new MockClock(now()->modify($when)), |
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.
wouldn't this be confusing if now()
is not a native clock currently ?
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.
If it's not a native clock, it's usually a mock clock. This behavior is desired to me, to do eg:
self::mockTime(); // freeze
//...
self::mockTime('+1 days'); // frozen time + 1 day
ab6b038
to
43d3143
Compare
43d3143
to
1eb775b
Compare
1eb775b
to
aaad65c
Compare
* Note that you should prefer injecting a ClockInterface or using | ||
* ClockAwareTrait when possible instead of using this function. |
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.
…lt (nicolas-grekas) This PR was merged into the 6.3 branch. Discussion ---------- [Clock] Make ClockAwareTrait use the global clock by default | Q | A | ------------- | --- | Branch? | 6.3 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | - | License | MIT | Doc PR | - Let's make `ClockAwareTrait` compatible with `Clock::now()` from #48642 by default. Commits ------- ec60013 [Clock] Make ClockAwareTrait use the global clock by default
Why is there a |
See discussion on #48564.
This PR adds 2 static methods and one function:
It also wires this global clock as a service so that injecting the
ClockInterface
or usingnow
/Clock::get()
returns the same time.Last but not least, this PR also provides a
ClockSensitiveTrait
to help write test cases that rely on the clock. This trait provides oneself::mockTime()
method and it restores the global clock after each test case.mockTime()
accepts either a string (eg'+1 days'
or'2022-12-22'
), a DTI instance, or a boolean (to freeze/restore the global clock).