Skip to content

Commit a787c8b

Browse files
committed
Make discovery more SOLID
1 parent 13bcb44 commit a787c8b

17 files changed

+351
-246
lines changed

src/ClassDiscovery.php

Lines changed: 57 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -2,93 +2,40 @@
22

33
namespace Http\Discovery;
44

5+
use Http\Discovery\Exception\DiscoveryFailedException;
6+
use Http\Discovery\Exception\StrategyUnavailableException;
57
use Http\Discovery\Exception\NotFoundException;
6-
use Http\Discovery\Exception\PuliNotAvailableException;
7-
use Http\Discovery\FallbackStrategy\HttpClients;
8-
use Http\Discovery\FallbackStrategy\DiactorosFactory;
9-
use Http\Discovery\FallbackStrategy\GuzzleFactory;
10-
use Puli\Discovery\Api\Discovery;
8+
use Http\Discovery\Strategy\DiactorosFactory;
9+
use Http\Discovery\Strategy\GuzzleFactory;
10+
use Http\Discovery\Strategy\HttpClients;
11+
use Http\Discovery\Strategy\Puli;
1112

1213
/**
1314
* Registry that based find results on class existence.
1415
*
1516
* @author David de Boer <[email protected]>
1617
* @author Márk Sági-Kazár <[email protected]>
18+
* @author Tobias Nyholm <[email protected]>
1719
*/
1820
abstract class ClassDiscovery
1921
{
2022
/**
21-
* @var GeneratedPuliFactory
22-
*/
23-
private static $puliFactory;
24-
25-
/**
26-
* @var Discovery
27-
*/
28-
private static $puliDiscovery;
29-
30-
/**
31-
* @return GeneratedPuliFactory
32-
*/
33-
public static function getPuliFactory()
34-
{
35-
if (null === self::$puliFactory) {
36-
if (!defined('PULI_FACTORY_CLASS')) {
37-
throw new PuliNotAvailableException('Puli Factory is not available');
38-
}
39-
40-
$puliFactoryClass = PULI_FACTORY_CLASS;
41-
42-
if (!class_exists($puliFactoryClass)) {
43-
throw new PuliNotAvailableException('Puli Factory class does not exist');
44-
}
45-
46-
self::$puliFactory = new $puliFactoryClass();
47-
}
48-
49-
return self::$puliFactory;
50-
}
51-
52-
/**
53-
* Sets the Puli factory.
23+
* A list of strategies to find classes.
5424
*
55-
* @param object $puliFactory
25+
* @var array
5626
*/
57-
public static function setPuliFactory($puliFactory)
58-
{
59-
if (!is_callable([$puliFactory, 'createRepository']) || !is_callable([$puliFactory, 'createDiscovery'])) {
60-
throw new \InvalidArgumentException('The Puli Factory must expose a repository and a discovery');
61-
}
62-
63-
self::$puliFactory = $puliFactory;
64-
self::$puliDiscovery = null;
65-
}
27+
public static $strategies = [
28+
Puli::class,
29+
HttpClients::class,
30+
GuzzleFactory::class,
31+
DiactorosFactory::class,
32+
];
6633

6734
/**
68-
* Resets the factory.
35+
* Discovery cache to make the second time we use discovery faster.
36+
* @var array
6937
*/
70-
public static function resetPuliFactory()
71-
{
72-
self::$puliFactory = null;
73-
self::$puliDiscovery = null;
74-
}
75-
76-
/**
77-
* Returns the Puli discovery layer.
78-
*
79-
* @return Discovery
80-
*/
81-
public static function getPuliDiscovery()
82-
{
83-
if (!isset(self::$puliDiscovery)) {
84-
$factory = self::getPuliFactory();
85-
$repository = $factory->createRepository();
86-
87-
self::$puliDiscovery = $factory->createDiscovery($repository);
88-
}
89-
90-
return self::$puliDiscovery;
91-
}
38+
private static $cache = [];
9239

9340
/**
9441
* Finds a class.
@@ -101,58 +48,62 @@ public static function getPuliDiscovery()
10148
*/
10249
public static function findOneByType($type)
10350
{
104-
try {
105-
return self::puliFindOneByType($type);
106-
} catch (PuliNotAvailableException $e) {
107-
if (false !== $class = HttpClients::findOneByType($type)) {
108-
return $class;
109-
} elseif (false !== $class = GuzzleFactory::findOneByType($type)) {
110-
return $class;
111-
} elseif (false !== $class = DiactorosFactory::findOneByType($type)) {
112-
return $class;
51+
$exceptions = [];
52+
53+
if (null !== $class = self::getFromCache($type)) {
54+
return $class;
55+
}
56+
57+
foreach (self::$strategies as $strategy) {
58+
try {
59+
$bindings = call_user_func($strategy.'::find', $type);
60+
} catch (StrategyUnavailableException $e) {
61+
$exceptions[] = $e;
62+
continue;
63+
}
64+
65+
foreach ($bindings as $binding) {
66+
if ($binding['condition']) {
67+
if (!self::evaluateCondition($binding['condition'])) {
68+
continue;
69+
}
70+
}
71+
72+
// save the result for later use
73+
self::storeInCache($type, $binding['class']);
74+
75+
return $binding['class'];
11376
}
114-
throw new NotFoundException('Could not find resource using Puli nor common Guzzle/Diactoros classes', 0, $e);
11577
}
78+
79+
throw new DiscoveryFailedException('Could not find resource using any discovery strategy', $exceptions);
11680
}
11781

11882
/**
119-
* Finds a class using Puli.
83+
* Get a value from cache
12084
*
121-
* @param $type
122-
*
123-
* @return string
85+
* @param string $type
12486
*
125-
* @throws NotFoundException
126-
* @throws PuliNotAvailableException
87+
* @return string|null
12788
*/
128-
private static function puliFindOneByType($type)
89+
private static function getFromCache($type)
12990
{
130-
$bindings = self::getPuliDiscovery()->findBindings($type);
131-
132-
foreach ($bindings as $binding) {
133-
if ($binding->hasParameterValue('depends')) {
134-
$dependency = $binding->getParameterValue('depends');
135-
136-
if (!self::evaluateCondition($dependency)) {
137-
continue;
138-
}
139-
}
140-
141-
// TODO: check class binding
142-
return $binding->getClassName();
91+
if (isset(self::$cache[$type])) {
92+
return self::$cache[$type];
14393
}
14494

145-
throw new NotFoundException(sprintf('Resource of type "%s" not found', $type));
95+
return null;
14696
}
14797

14898
/**
149-
* Finds a resource.
99+
* Store a value in cache
150100
*
151-
* @return object
101+
* @param string $type
102+
* @param string $class
152103
*/
153-
public static function find()
104+
private static function storeInCache($type, $class)
154105
{
155-
throw new \LogicException('Not implemented');
106+
self::$cache[$type] = $class;
156107
}
157108

158109
/**
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
namespace Http\Discovery\Exception;
4+
5+
/**
6+
* Thrown when all discovery strategies fails to find a resource.
7+
*
8+
* @author Tobias Nyholm <[email protected]>
9+
*/
10+
final class DiscoveryFailedException extends \RuntimeException
11+
{
12+
/**
13+
* @var array
14+
*/
15+
private $exceptions;
16+
17+
/**
18+
*
19+
* @param $exceptions
20+
*/
21+
public function __construct($message, array $exceptions = [])
22+
{
23+
$this->exceptions = $exceptions;
24+
25+
parent::__construct($message, 0, array_shift($exceptions));
26+
}
27+
28+
/**
29+
* @return array
30+
*/
31+
public function getExceptions()
32+
{
33+
return $this->exceptions;
34+
}
35+
}

src/Exception/PuliNotAvailableException.php renamed to src/Exception/PuliUnavailableException.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
*
88
* @author Tobias Nyholm <[email protected]>
99
*/
10-
class PuliNotAvailableException extends \RuntimeException
10+
class PuliUnavailableException extends StrategyUnavailableException
1111
{
1212
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace Http\Discovery\Exception;
4+
5+
/**
6+
* This exception is thrown when we cannot use a discovery strategy. This is *not* thrown when
7+
* the discovery fails to find a class.
8+
*
9+
* @author Tobias Nyholm <[email protected]>
10+
*/
11+
class StrategyUnavailableException extends \RuntimeException
12+
{
13+
14+
}

src/FallbackStrategy/DiactorosFactory.php

Lines changed: 0 additions & 41 deletions
This file was deleted.

src/FallbackStrategy/FallbackStrategy.php

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/FallbackStrategy/GuzzleFactory.php

Lines changed: 0 additions & 41 deletions
This file was deleted.

0 commit comments

Comments
 (0)