Skip to content

Commit

Permalink
Attempts to resolved objects completely whenever possible (#756)
Browse files Browse the repository at this point in the history
Closes #752
  • Loading branch information
theofidry committed Jun 28, 2017
1 parent bc9edbe commit 8c7cc34
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 34 deletions.
40 changes: 40 additions & 0 deletions fixtures/Entity/InitializationOrder/Address.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/*
* This file is part of the Alice package.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Nelmio\Alice\Entity\InitializationOrder;

final class Address
{
private $country;
private $city;

public function getCountry()
{
return $this->country;
}

public function setCountry(string $country)
{
$this->country = $country;
}

public function getCity(): string
{
return $this->city;
}

public function setCity(string $city)
{
$this->city = $city;
}
}
30 changes: 30 additions & 0 deletions fixtures/Entity/InitializationOrder/Person.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/*
* This file is part of the Alice package.
*
* (c) Nelmio <hello@nelm.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Nelmio\Alice\Entity\InitializationOrder;

final class Person
{
private $city;
private $country;

public static function createWithAddress($address)
{
$instance = new self();

$instance->city = $address->getCity();
$instance->country = $address->getCountry();

return $instance;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
use Nelmio\Alice\Generator\Resolver\Value\ChainableValueResolverInterface;
use Nelmio\Alice\IsAServiceTrait;
use Nelmio\Alice\Throwable\Exception\Generator\ObjectGenerator\ObjectGeneratorNotFoundExceptionFactory;
use Nelmio\Alice\Throwable\Exception\Generator\Resolver\CircularReferenceException;
use Nelmio\Alice\Throwable\Exception\Generator\Resolver\FixtureNotFoundExceptionFactory;
use Nelmio\Alice\Throwable\Exception\Generator\Resolver\UnresolvableValueException;
use Nelmio\Alice\Throwable\Exception\Generator\Resolver\UnresolvableValueExceptionFactory;
Expand All @@ -40,6 +41,11 @@ final class FixtureReferenceResolver implements ChainableValueResolverInterface,
*/
private $generator;

/**
* @var array
*/
private $incompleteObjects = [];

public function __construct(ObjectGeneratorInterface $generator = null)
{
$this->generator = $generator;
Expand Down Expand Up @@ -104,19 +110,26 @@ private function getReferredFixture(string $id, ResolvedFixtureSet $set): Fixtur
* @param string $referredFixtureId
* @param ResolvedFixtureSet $fixtureSet
* @param GenerationContext $context
* @param bool|null $passIncompleteObject
*
* @return ResolvedValueWithFixtureSet
*/
private function resolveReferredFixture(
FixtureIdInterface $referredFixture,
string $referredFixtureId,
ResolvedFixtureSet $fixtureSet,
GenerationContext $context
GenerationContext $context,
bool $passIncompleteObject = null
): ResolvedValueWithFixtureSet {
if ($fixtureSet->getObjects()->has($referredFixture)) {
$referredObject = $fixtureSet->getObjects()->get($referredFixture);

if ($referredObject instanceof CompleteObject || false === $context->needsCompleteGeneration()) {
if ($referredObject instanceof CompleteObject
|| $passIncompleteObject
|| array_key_exists($referredFixtureId, $this->incompleteObjects)
) {
$this->incompleteObjects[$referredFixtureId] = true;

return new ResolvedValueWithFixtureSet(
$referredObject->getInstance(),
$fixtureSet
Expand All @@ -125,17 +138,38 @@ private function resolveReferredFixture(
}

// Object is either not completely generated or has not been generated at all yet
// Attempts to generate the fixture completely
if (false === $referredFixture instanceof FixtureInterface) {
throw FixtureNotFoundExceptionFactory::create($referredFixtureId);
}

$context->markIsResolvingFixture($referredFixtureId);
$objects = $this->generator->generate($referredFixture, $fixtureSet, $context);
$fixtureSet = $fixtureSet->withObjects($objects);
try {
$needsCompleteGeneration = $context->needsCompleteGeneration();

if (!$passIncompleteObject) {
$context->markAsNeedsCompleteGeneration();
}
$context->markIsResolvingFixture($referredFixtureId);
$objects = $this->generator->generate($referredFixture, $fixtureSet, $context);
$fixtureSet = $fixtureSet->withObjects($objects);

return new ResolvedValueWithFixtureSet(
$fixtureSet->getObjects()->get($referredFixture)->getInstance(),
$fixtureSet
);
if (false === $needsCompleteGeneration) {
$context->unmarkAsNeedsCompleteGeneration();
}

return new ResolvedValueWithFixtureSet(
$fixtureSet->getObjects()->get($referredFixture)->getInstance(),
$fixtureSet
);
} catch (CircularReferenceException $exception) {
if (false === $needsCompleteGeneration && null !== $passIncompleteObject) {
throw $exception;
}

$context->unmarkAsNeedsCompleteGeneration();

// Could not completely generate the fixtures, fallback to generating an incomplete object
return $this->resolveReferredFixture($referredFixture, $referredFixtureId, $fixtureSet, $context, true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,30 +121,6 @@ public function testIfTheReferenceRefersToACompletelyGeneratedFixtureThenReturns
$this->assertEquals($expected, $actual);
}

public function testIfTheReferenceRefersToAnInstantiatedFixtureThatDoesNotRequireToBeCompleteThenReturnsItsInstance()
{
$value = new FixtureReferenceValue('dummy');
$fixture = new FakeFixture();
$set = ResolvedFixtureSetFactory::create(
null,
null,
(new ObjectBag())->with(
new SimpleObject(
'dummy',
$expectedInstance = new \stdClass())
)
);
$scope = [];
$context = new GenerationContext();

$expected = new ResolvedValueWithFixtureSet($expectedInstance, $set);

$resolver = new FixtureReferenceResolver(new FakeObjectGenerator());
$actual = $resolver->resolve($value, $fixture, $set, $scope, $context);

$this->assertEquals($expected, $actual);
}

public function testIfTheReferenceRefersToAnInstantiatedFixtureAndRequiresToBeCompleteThenGenerateIt()
{
$value = new FixtureReferenceValue('dummy');
Expand Down Expand Up @@ -216,6 +192,7 @@ public function testIfTheReferenceRefersToANonInstantiatedFixtureThenGenerateItB

$generatorContext = new GenerationContext();
$generatorContext->markIsResolvingFixture('dummy');
$generatorContext->markAsNeedsCompleteGeneration();

$generatorProphecy = $this->prophesize(ObjectGeneratorInterface::class);
$generatorProphecy
Expand All @@ -239,8 +216,10 @@ public function testIfTheReferenceRefersToANonInstantiatedFixtureThenGenerateItB
$resolver = new FixtureReferenceResolver($generator);
$actual = $resolver->resolve($value, $fixture, $set, $scope, $context);

$generatorContext->unmarkAsNeedsCompleteGeneration();

$this->assertEquals($expected, $actual);
$this->assertEquals($context, $generatorContext);
$this->assertEquals($generatorContext, $context);

$generatorProphecy->generate(Argument::cetera())->shouldHaveBeenCalledTimes(1);
}
Expand Down
37 changes: 37 additions & 0 deletions tests/Loader/LoaderIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3339,5 +3339,42 @@ public function provideFixturesToGenerate()
],
],
];

// https://github.com/nelmio/alice/issues/752
yield 'calls and factory order' => (function () {
return [
[
\Nelmio\Alice\Entity\InitializationOrder\Address::class => [
'address' => [
'country' => 'France',
'city' => 'Paris',
],
],
\Nelmio\Alice\Entity\InitializationOrder\Person::class => [
'person' => [
'__factory' => [
'createWithAddress' => [
'@address',
],
],
],
],
],
[
'parameters' => [],
'objects' => [
'address' => $address = (function () {
$address = new \Nelmio\Alice\Entity\InitializationOrder\Address();

$address->setCountry('France');
$address->setCity('Paris');

return $address;
})(),
'person' => \Nelmio\Alice\Entity\InitializationOrder\Person::createWithAddress($address)
],
],
];
})();
}
}

0 comments on commit 8c7cc34

Please sign in to comment.