Skip to content

Commit 270a11e

Browse files
Merge pull request #71 from Rareloop/feature/template-controller-di
Increase template controller DI support
2 parents 6922be5 + b234850 commit 270a11e

37 files changed

Lines changed: 1328 additions & 9 deletions

src/Application.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public function register($provider)
162162
}
163163

164164
if (is_string($provider)) {
165-
$provider = new $provider($this);
165+
$provider = $this->make($provider);
166166
}
167167

168168
if (method_exists($provider, 'register')) {

src/Bootstrappers/RegisterRequestHandler.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,9 @@ public function bootstrap(Application $app)
1313
if ($config->get('app.debug')) {
1414
$app->detectWhenRequestHasNotBeenHandled();
1515
}
16+
17+
$app->bind(\WP_Query::class, function () {
18+
return $GLOBALS['wp_query'];
19+
});
1620
}
1721
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rareloop\Lumberjack\Exceptions;
4+
5+
class MismatchedContextException extends UnresolvableContextException
6+
{
7+
public static function forIncorrectClass(string $expectedClass, mixed $actualValue): self
8+
{
9+
$actualType = is_object($actualValue) ? $actualValue::class : gettype($actualValue);
10+
11+
return new static(
12+
"Resolved a WordPress object, but it was of type [{$actualType}] " .
13+
"instead of the expected [{$expectedClass}]."
14+
);
15+
}
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Rareloop\Lumberjack\Exceptions;
4+
5+
class MissingContextException extends UnresolvableContextException
6+
{
7+
public static function forType(string $expectedClass, mixed $actualObject): self
8+
{
9+
$actualType = get_debug_type($actualObject);
10+
11+
return new static(
12+
"Could not resolve context for typehint [{$expectedClass}]. " .
13+
"The current WordPress queried object is [{$actualType}]."
14+
);
15+
}
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Rareloop\Lumberjack\Exceptions;
4+
5+
use Exception;
6+
7+
class UnresolvableContextException extends Exception
8+
{
9+
}

src/Helpers.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,12 @@ public static function config($key, $default = null)
4141

4242
public static function view($template, $context = [], $statusCode = 200, $headers = [])
4343
{
44-
return new TimberResponse($template, $context, $statusCode, $headers);
44+
return static::app()->make(TimberResponse::class, [
45+
'twigTemplate' => $template,
46+
'context' => $context,
47+
'status' => $statusCode,
48+
'headers' => $headers,
49+
]);
4550
}
4651

4752
public static function route($name, $params = [])
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace Rareloop\Lumberjack\Http\Resolvers;
4+
5+
use Illuminate\Support\Arr;
6+
use Invoker\ParameterResolver\ParameterResolver;
7+
use Rareloop\Lumberjack\Exceptions\MismatchedContextException;
8+
use Rareloop\Lumberjack\Exceptions\MissingContextException;
9+
use ReflectionFunctionAbstract;
10+
11+
abstract class AbstractContextResolver implements ParameterResolver
12+
{
13+
public function getParameters(
14+
ReflectionFunctionAbstract $reflection,
15+
array $providedParameters,
16+
array $resolvedParameters
17+
): array {
18+
foreach ($reflection->getParameters() as $parameter) {
19+
if (Arr::has($resolvedParameters, $parameter->getPosition())) {
20+
continue;
21+
}
22+
23+
$type = $parameter->getType();
24+
25+
if (!$type || $type->isBuiltin()) {
26+
continue;
27+
}
28+
29+
$className = $type->getName();
30+
31+
if (!$this->canResolveClass($className)) {
32+
continue;
33+
}
34+
35+
try {
36+
$context = $this->getContext();
37+
38+
if (is_null($context)) {
39+
throw MissingContextException::forType($className, $context);
40+
}
41+
42+
if (!$this->isValidContext($context, $className)) {
43+
throw MismatchedContextException::forIncorrectClass($className, $context);
44+
}
45+
46+
$resolvedObject = $this->resolveObject($className, $context);
47+
48+
if (!is_null($resolvedObject) && !$resolvedObject instanceof $className) {
49+
throw MismatchedContextException::forIncorrectClass($className, $resolvedObject);
50+
}
51+
52+
$resolvedParameters[$parameter->getPosition()] = $resolvedObject;
53+
} catch (MissingContextException | MismatchedContextException $e) {
54+
// If the context is entirely missing or mismatched, we allow null if the typehint supports it
55+
if (!$parameter->allowsNull()) {
56+
throw $e;
57+
}
58+
59+
$resolvedParameters[$parameter->getPosition()] = null;
60+
}
61+
}
62+
63+
return $resolvedParameters;
64+
}
65+
66+
/**
67+
* Get the raw context object to resolve from (e.g. WP_Post, WP_Term, WP_Query).
68+
* Defaults to the current WordPress queried object.
69+
*
70+
* @return mixed
71+
*/
72+
protected function getContext(): mixed
73+
{
74+
return get_queried_object();
75+
}
76+
77+
/**
78+
* Determine if this resolver can handle the given class type-hint.
79+
*
80+
* @param string $className
81+
* @return bool
82+
*/
83+
abstract protected function canResolveClass(string $className): bool;
84+
85+
/**
86+
* Determine if the current context is valid for this resolver.
87+
*
88+
* @param mixed $context
89+
* @param string $className
90+
* @return bool
91+
*/
92+
abstract protected function isValidContext(mixed $context, string $className): bool;
93+
94+
/**
95+
* Build the concrete object instance from the raw context.
96+
*
97+
* @param string $className
98+
* @param mixed $context
99+
* @return mixed
100+
*/
101+
abstract protected function resolveObject(string $className, mixed $context): mixed;
102+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace Rareloop\Lumberjack\Http\Resolvers;
4+
5+
use Rareloop\Lumberjack\Application;
6+
use Timber\PostQuery as TimberPostQuery;
7+
use Timber\PostCollectionInterface;
8+
use Timber\Timber;
9+
use WP_Query;
10+
11+
class PostQueryResolver extends AbstractContextResolver
12+
{
13+
public function __construct(protected Application $app)
14+
{
15+
}
16+
17+
protected function canResolveClass(string $className): bool
18+
{
19+
return is_a($className, TimberPostQuery::class, true)
20+
|| is_a($className, PostCollectionInterface::class, true);
21+
}
22+
23+
protected function isValidContext(mixed $context, string $className): bool
24+
{
25+
return is_a($context, WP_Query::class);
26+
}
27+
28+
protected function getContext(): mixed
29+
{
30+
return $this->app->get(WP_Query::class);
31+
}
32+
33+
protected function resolveObject(string $className, mixed $context): mixed
34+
{
35+
// If they asked for the interface or the base Timber PostQuery, use the factory
36+
if ($className === PostCollectionInterface::class || $className === TimberPostQuery::class) {
37+
return Timber::get_posts($context);
38+
}
39+
40+
// If it's a subclass (like Rareloop\Lumberjack\PostQuery), we must instantiate it manually
41+
// to ensure we get the correct instance type.
42+
return new $className($context);
43+
}
44+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace Rareloop\Lumberjack\Http\Resolvers;
4+
5+
use Rareloop\Lumberjack\Post;
6+
use Timber\Post as TimberPost;
7+
use Timber\Timber;
8+
use Timber\CoreEntityInterface;
9+
use WP_Post;
10+
11+
class PostResolver extends AbstractContextResolver
12+
{
13+
protected function canResolveClass(string $className): bool
14+
{
15+
return is_a($className, Post::class, true)
16+
|| is_a($className, TimberPost::class, true);
17+
}
18+
19+
protected function isValidContext(mixed $context, string $className): bool
20+
{
21+
return is_a($context, WP_Post::class) || is_a($context, CoreEntityInterface::class);
22+
}
23+
24+
protected function resolveObject(string $className, mixed $context): mixed
25+
{
26+
return Timber::get_post($context);
27+
}
28+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Rareloop\Lumberjack\Http\Resolvers;
4+
5+
use Rareloop\Lumberjack\Term;
6+
use Timber\Term as TimberTerm;
7+
use Timber\Timber;
8+
use Timber\CoreEntityInterface;
9+
use WP_Term;
10+
11+
class TermResolver extends AbstractContextResolver
12+
{
13+
protected function canResolveClass(string $className): bool
14+
{
15+
return is_a($className, Term::class, true) || is_a($className, TimberTerm::class, true);
16+
}
17+
18+
protected function isValidContext(mixed $context, string $className): bool
19+
{
20+
return is_a($context, WP_Term::class) || is_a($context, CoreEntityInterface::class);
21+
}
22+
23+
protected function resolveObject(string $className, mixed $context): mixed
24+
{
25+
return Timber::get_term($context);
26+
}
27+
}

0 commit comments

Comments
 (0)