Skip to content

Commit bbf6902

Browse files
committed
Added begin of Link resolving
1 parent ae18af2 commit bbf6902

15 files changed

+257
-105
lines changed

src/Exceptions/InvalidSerializedValue.php

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,39 @@
33
namespace Whitecube\Links\Exceptions;
44

55
use InvalidArgumentException;
6+
use Whitecube\Links\Resolvers\Archive;
67

78
class InvalidSerializedValue extends InvalidArgumentException
89
{
910
/**
10-
* Create a new Exception for an invalid serialized array value.
11+
* Create a new Exception for an invalid serialized inline tag value.
1112
*/
12-
public static function forArray(): never
13+
public static function inlineTagSyntax(string $tag): static
1314
{
14-
throw new self('Provided serialized link array should at least contain a "key" index.');
15+
return new self(sprintf('Provided serialized inline tag should match syntax "@link(key:value)", got "%s"', $tag));
1516
}
17+
1618
/**
17-
* Create a new Exception for an invalid serialized inline tag value.
19+
* Create a new Exception for an invalid serialized array value because of a missing "resolver" key.
1820
*/
19-
public static function forInlineTag(string $tag): never
21+
public static function missingResolver(): static
2022
{
21-
throw new self(sprintf('Provided serialized inline tag should match syntax "@link(key:value)", got "%s"', $tag));
23+
return new self('Provided serialized link value should at least contain a "resolver" attribute.');
24+
}
25+
26+
/**
27+
* Create a new Exception for an invalid serialized array value because of a missing "resolver" key.
28+
*/
29+
public static function ambiguousArchiveResolver(Archive $archive, string $key): static
30+
{
31+
$available = implode(', ', array_map(fn($key) => '"'.$key.'"', array_filter([
32+
$archive->getIndex()?->key,
33+
$archive->getItems()?->key,
34+
])));
35+
36+
return new self(sprintf(
37+
'Provided serialized link value is targetting an ambiguous archive resolver (available: %s, got "%s").',
38+
$available, $key
39+
));
2240
}
2341
}

src/Link.php

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,62 +2,53 @@
22

33
namespace Whitecube\Links;
44

5+
use Illuminate\Support\Facades\App;
56
use Whitecube\Links\Exceptions\InvalidSerializedValue;
67

78
class Link
89
{
910
/**
10-
* The URL resolver's identification key.
11+
* The resolved URL.
1112
*/
12-
protected string $key;
13+
public readonly string $url;
1314

1415
/**
15-
* The represented resource's immutable identifier.
16+
* The eventual extra provided arguments.
1617
*/
17-
protected null|int|string $id;
18+
protected array $arguments;
1819

1920
/**
20-
* The default displayable title.
21+
* The defined title attribute for this link.
2122
*/
22-
protected string $title;
23+
protected ?string $title;
2324

2425
/**
25-
* The eventual extra arguments for the URL resolver.
26+
* The resolver used to create this link.
2627
*/
27-
protected array $arguments = [];
28+
protected ResolverInterface $resolver;
2829

2930
/**
30-
* Create a new Link instance.
31+
* The eventual variant represented by this link.
3132
*/
32-
public function __construct(string $key, null|int|string $id = null)
33-
{
34-
$this->key = $key;
35-
$this->id = $id;
36-
}
33+
protected ?Variant $variant;
3734

3835
/**
39-
* Create a new Link instance dynamically.
36+
* Create a new Link instance.
4037
*/
41-
public static function make(string $key, null|int|string $id = null): static
38+
public function __construct(string $url, ResolverInterface $resolver, ?Variant $variant = null, array $arguments = [])
4239
{
43-
return new static($key, $id);
40+
$this->url = $url;
41+
$this->resolver = $resolver;
42+
$this->variant = $variant;
43+
$this->arguments = $arguments;
4444
}
4545

4646
/**
4747
* Create a link instance from serialized array.
4848
*/
4949
public static function fromArray(array $value): static
5050
{
51-
if(! isset($value['key'])) {
52-
return InvalidSerializedValue::forArray();
53-
}
54-
55-
$instance = static::make($value['key'], $value['id'] ?? null);
56-
57-
unset($value['key']);
58-
unset($value['id']);
59-
60-
return $instance->arguments($value);
51+
return App::make(Manager::class)->resolve($value);
6152
}
6253

6354
/**
@@ -68,7 +59,7 @@ public static function fromInlineTag(string $value): static
6859
preg_match('/^\\@link\\((.+?)\\)$/', trim($value), $matches);
6960

7061
if(! ($matches[1] ?? null)) {
71-
return InvalidSerializedValue::forInlineTag($value);
62+
throw InvalidSerializedValue::inlineTagSyntax($value);
7263
}
7364

7465
$data = array_reduce(explode(',', $matches[1]), function ($data, $pair) {
@@ -81,20 +72,12 @@ public static function fromInlineTag(string $value): static
8172
return static::fromArray($data);
8273
}
8374

84-
/**
85-
* Get the link's resolver identifying key
86-
*/
87-
public function getResolverKey(): string
88-
{
89-
return $this->key;
90-
}
91-
9275
/**
9376
* Define the link's default displayable title.
9477
*/
9578
public function title(string $title): static
9679
{
97-
$this->title = $title;
80+
$this->title = trim($title) ?: null;
9881

9982
return $this;
10083
}
@@ -104,7 +87,7 @@ public function title(string $title): static
10487
*/
10588
public function getTitle(): string
10689
{
107-
return $this->title;
90+
return $this->title ?? $this->resolver->getTitle($this->variant);
10891
}
10992

11093
/**
@@ -136,10 +119,11 @@ public function argument(string $attribute, mixed $value): static
136119
*/
137120
public function toArray(): array
138121
{
139-
return array_filter(array_merge([
140-
'key' => $this->key,
141-
'id' => $this->id,
142-
], $this->arguments));
122+
return array_filter([
123+
'resolver' => $this->resolver->key,
124+
'variant' => $this->variant?->getKey(),
125+
'data' => $this->arguments ?: null,
126+
]);
143127
}
144128

145129
/**

src/Manager.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Whitecube\Links\Resolvers\Route;
77
use Whitecube\Links\Resolvers\Archive;
88
use Whitecube\Links\Exceptions\ResolverNotFound;
9+
use Whitecube\Links\Exceptions\InvalidSerializedValue;
910

1011
class Manager
1112
{
@@ -50,6 +51,26 @@ public function register(ResolverInterface $resolver): ResolverInterface
5051
return $resolver;
5152
}
5253

54+
/**
55+
* Transform a serialized link value into a proper resolved Link instance.
56+
*/
57+
public function resolve(array $value, bool $silent = false): ?Link
58+
{
59+
if(! isset($value['resolver'])) {
60+
throw InvalidSerializedValue::missingResolver();
61+
}
62+
63+
$resolver = ($silent)
64+
? $this->tryFor($value['resolver'])
65+
: $this->for($value['resolver']);
66+
67+
if(! $resolver) {
68+
return null;
69+
}
70+
71+
return $resolver->resolve($value, $silent);
72+
}
73+
5374
/**
5475
* Retrieve a registered resolver from the links resolvers repository
5576
* and throw an exception if not defined.

src/ResolverInterface.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ interface ResolverInterface
99
* itself or a more appropriate/specific resolver if available.
1010
*/
1111
public function for(string $key): ?ResolverInterface;
12+
13+
/**
14+
* Instantiate a Link object based on provided serialized value.
15+
*/
16+
public function resolve(array $value, bool $silent): ?Link;
1217

1318
/**
1419
* Transform the resolver into an available Link Option.
1520
*/
1621
public function toOption(): null|OptionInterface|OptionsCollection;
17-
18-
/**
19-
* Generate the effective URL.
20-
*/
21-
public function resolve(array $arguments = []): string;
2222
}

src/Resolvers/Archive.php

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
namespace Whitecube\Links\Resolvers;
44

55
use Closure;
6+
use Whitecube\Links\Link;
67
use Whitecube\Links\OptionPanel;
78
use Whitecube\Links\OptionInterface;
89
use Whitecube\Links\OptionsCollection;
910
use Whitecube\Links\ResolverInterface;
11+
use Whitecube\Links\Exceptions\InvalidSerializedValue;
1012

1113
class Archive implements ResolverInterface
1214
{
@@ -50,6 +52,14 @@ public function index(Closure $setup): static
5052
return $this;
5153
}
5254

55+
/**
56+
* Get the eventual defined index URL resolver.
57+
*/
58+
public function getIndex(): ?ArchiveIndexRoute
59+
{
60+
return $this->index;
61+
}
62+
5363
/**
5464
* Define the archive's items URLs resolver.
5565
*/
@@ -62,6 +72,14 @@ public function items(Closure $setup): static
6272
return $this;
6373
}
6474

75+
/**
76+
* Get the eventual defined items URL resolver.
77+
*/
78+
public function getItems(): ?ArchiveItemsRoute
79+
{
80+
return $this->items;
81+
}
82+
6583
/**
6684
* Check if this resolver is suited for the provided key and return
6785
* itself or a more appropriate/specific resolver if available.
@@ -73,6 +91,18 @@ public function for(string $key): ?ResolverInterface
7391
?? $this->items?->for($key)
7492
?? null;
7593
}
94+
95+
/**
96+
* Instantiate a Link object based on provided serialized value.
97+
*/
98+
public function resolve(array $value, bool $silent): ?Link
99+
{
100+
if(! $silent) {
101+
throw InvalidSerializedValue::ambiguousArchiveResolver($this, $value['resolver'] ?? $this->key);
102+
}
103+
104+
return null;
105+
}
76106

77107
/**
78108
* Transform the resolver into an available Link Option.
@@ -103,12 +133,4 @@ protected function configureOptionChoicesPanel(OptionPanel $panel): void
103133

104134
$panel->archive($this->items->toOption());
105135
}
106-
107-
/**
108-
* Generate the effective URL.
109-
*/
110-
public function resolve(array $arguments = []): string
111-
{
112-
return '#'; // TODO
113-
}
114136
}

src/Resolvers/ArchiveIndexRoute.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Whitecube\Links\Resolvers;
44

5+
use Whitecube\Links\Link;
56
use Whitecube\Links\OptionInterface;
67
use Whitecube\Links\OptionsCollection;
78
use Whitecube\Links\ResolverInterface;
@@ -33,6 +34,14 @@ public function for(string $key): ?ResolverInterface
3334
return ($this->key === $key) ? $this : null;
3435
}
3536

37+
/**
38+
* Instantiate a Link object based on provided serialized value.
39+
*/
40+
public function resolve(array $value, bool $silent): ?Link
41+
{
42+
return null;
43+
}
44+
3645
/**
3746
* Transform the resolver into an available Link Option.
3847
*/

src/Resolvers/ArchiveItemsRoute.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Whitecube\Links\Resolvers;
44

5+
use Whitecube\Links\Link;
56
use Whitecube\Links\OptionInterface;
67
use Whitecube\Links\OptionsCollection;
78
use Whitecube\Links\ResolverInterface;
@@ -34,6 +35,14 @@ public function for(string $key): ?ResolverInterface
3435
return ($this->key === $key) ? $this : null;
3536
}
3637

38+
/**
39+
* Instantiate a Link object based on provided serialized value.
40+
*/
41+
public function resolve(array $value, bool $silent): ?Link
42+
{
43+
return null;
44+
}
45+
3746
/**
3847
* Transform the resolver into an available Link Option.
3948
*/

src/Resolvers/Concerns/ResolvesRoutes.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ public function getRouteArgument(string $key): mixed
5252
}
5353

5454
/**
55-
* Generate the effective URL.
55+
* Generate the route's effective URL.
5656
*/
57-
public function resolve(array $arguments = []): string
57+
protected function generateUrl(array $arguments = []): string
5858
{
5959
return URL::route($this->getRouteName(), array_merge(
6060
$this->getRouteArguments(),

src/Resolvers/Route.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Whitecube\Links\Resolvers;
44

5+
use Whitecube\Links\Link;
56
use Whitecube\Links\OptionInterface;
67
use Whitecube\Links\OptionsCollection;
78
use Whitecube\Links\ResolverInterface;
@@ -32,6 +33,18 @@ public function for(string $key): ?ResolverInterface
3233
{
3334
return ($this->key === $key) ? $this : null;
3435
}
36+
37+
/**
38+
* Instantiate a Link object based on provided serialized value.
39+
*/
40+
public function resolve(array $value, bool $silent): ?Link
41+
{
42+
return new Link(
43+
url: $this->generateUrl($value['data'] ?? []),
44+
arguments: $value['data'] ?? [],
45+
resolver: $this,
46+
);
47+
}
3548

3649
/**
3750
* Transform the resolver into an available Link Option.

0 commit comments

Comments
 (0)