-
-
Notifications
You must be signed in to change notification settings - Fork 328
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
Implemented method calling via __calls #666
Conversation
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.
Besides my comment, a few missing changes:
- Update the service definition for the Symfony bridge as well
- For the local tests you should have a
bin/tests.sh
script you can run (which runs the tests for the Symfony bridge as well) - You can remove the TODO from the doc
- I would like to see an integration test as well (in
LoaderIntegrationTest
), which ensures it works with both theNativeLoader
and the loader registered in Symfony as well
/** | ||
* @param string $title | ||
*/ | ||
public function setTitle($title) |
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.
you can add the typehint in favour of the phpdoc here
class Dummy | ||
{ | ||
private $title; | ||
private $foo = 0; |
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.
$counter
? Even if we don't know the counter of what we would at least get that it's a number
@@ -23,9 +24,9 @@ class FakeCaller implements CallerInterface | |||
use NotCallableTrait; | |||
|
|||
/** | |||
* @inheritdoc | |||
* {@inheritdoc} |
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.
remove the brackets, they are here for when there is text:
interface IFoo
{
/**
* Something
*/
function bar();
}
class Foo implements IFoo
{
/**
* @inherit // equivalent to "pick all the stuff of the parent method"
*/
function bar();
/**
* {@inherit} // equivalent to "replace this bit by the stuff of the parent method"
*
* My comments/phpdoc
*/
function bar();
}
/**
* My comments //ignore the phpdoc of the parent method
*/
function bar();
I've taken that from a draft of the PSR-5, it's still a draft so may change, but as the whole project follows the convention I would prefer to keep it (changing it doesn't make much sense at this point IMO)
@@ -50,4 +50,20 @@ public function isEmpty(): bool | |||
{ | |||
return [] === $this->methodCalls; | |||
} | |||
|
|||
/** | |||
* {@inheritdoc} |
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.
same as above
} | ||
|
||
/** | ||
* {@inheritdoc} |
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.
same as above
|
||
foreach ($calls as $methodCall) { | ||
$methodCall = $this->processArguments($methodCall, $fixture, $fixtureSet, $scope, $context); | ||
$scope[$methodCall->getMethod()] = $methodCall; |
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 don't think we need to add the method name to the scope. When we inject a property value, we do so because we may need the evaluated value later:
Dummy:
dummy:
foo: '<evaluate_foo()>'
bar: '$foo' # value of '<evaluate_foo()>' (which may differ from '@self->foo')*
*: @self->foo
will try to access to the foo
property of the object, which might have a different value if the value has been set via a setter which doesn't just do a $this>foo = $foo
.
What you are doing is enabling:
Dummy:
dummy:
__calls:
- setFoo: [ '<evaluate_foo()>' ]
- setFoo: [ '$setFoo' ]
which I don't think is very useful and even error prone as as you can see in the case above, you may override the value if doing successive calls
$dummyProphecy = $this->prophesize(Dummy::class); | ||
$dummyProphecy->setTitle('foo_title')->shouldBeCalled(); | ||
$dummyProphecy->addFoo()->shouldBeCalledTimes(2); | ||
$dummy = $dummyProphecy->reveal(); |
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.
to be consistent with the existing codebase, I would add a /** @var Dummy $dummy*/
inline phpdoc between L73 and L74
{ | ||
$dummyProphecy = $this->prophesize(Dummy::class); | ||
$dummyProphecy->setTitle('foo_title')->shouldBeCalled(); | ||
$dummyProphecy->addFoo()->shouldBeCalledTimes(2); |
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 would put shouldBeCalled()
here as when you are creating the prophecy, you don't care of how much calls are being made at this point, it's a check you are doing in the end. So at the end of the test you should add:
$dummyProphecy->setTitle(Argument:any())->shouldHaveCalledTimes(1);
$dummyProphecy->addFoo()->shouldBeCalledTimes(2);
granted that in this case, this might seem a bit redundant, but it's a practice that usually makes it easier to follow IMO, and again let's try to stay consistent with the codebase
null, | ||
new PropertyBag(), | ||
(new MethodCallBag()) | ||
->with(new SimpleMethodCall('setTitle', [$titleValue = new FakeValue()])) |
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 would add a second call on setTitle
to make sure the second overrides the first
} | ||
} | ||
|
||
return $methodCall->withArguments($arguments); |
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.
you should return [$methodCall->withArguments($arguments), $fixtureSet]
. The reason $result
contains both the a value and the set is that the set may have changed during the resolution. A simple example:
Dummy:
dummy2:
__construct:
- '@dummy1' # while resolving the value, the fixture `@dummy1` will be generated
dummy1:
foo: 'foo'
And if the $fixtureSet
is not properly updated, when it will be the turn of dummy1
, instead of finding the object already generated, it will generated again (which will also break the dependency between dummy2
and dummy1
as dymmy2#dummy1
will no longer be dummy1
)
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.
$fixtureSet
here is passed by-ref, so it is already updated.
Do you prefer returning an array with the new fixtureSet instead of passing it by reference?
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.
Ah I missed that, yes please, I prefer explicit returned values over passing them by references :)
Thanks for the PR @alekitto, that's some big work :) There is a few changes still to do, but the hardest has been made. How was the dive in the code? I tried to make it readable but if you have some feedbacks and things that looked really weird don't hesitate to point them out! |
…ne from docblocks
I made some changes, tomorrow i'll write an integration test. |
The services can be found in src/Bridge/Symfony/Resources/config. Basically It's like a traditional bundle, but shipped here instead of a dedicated library (it's easier for maintenance on my end). |
@alekitto tell me when you need a last review, AFAICS there's only one comment left and should be ready to ship. |
Should be all done now |
Thanks very much @alekitto, that's a nice one :) |
Added a
SimpleCaller
class to handle method calls via__calls
as documented here: https://github.com/nelmio/alice/blob/master/doc/complete-reference.md#calling-methods