Skip to content

Commit e785e0d

Browse files
committed
Improve Modifier documentation
1 parent 9382af6 commit e785e0d

File tree

2 files changed

+176
-41
lines changed

2 files changed

+176
-41
lines changed

components/Modifier.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ public function withScheme(Stringable|string|null $scheme): static
223223
return new static($this->uri->withScheme(self::normalizeComponent($scheme, $this->uri)));
224224
}
225225

226-
public function withUserInfo(Stringable|string|null $user, Stringable|string|null $password): static
226+
public function withUserInfo(Stringable|string|null $username, Stringable|string|null $password): static
227227
{
228228
if ($this->uri instanceof Rfc3986Uri) {
229-
$userInfo = Encoder::encodeUser($user);
229+
$userInfo = Encoder::encodeUser($username);
230230
if (null !== $password) {
231231
$userInfo .= ':'.Encoder::encodePassword($password);
232232
}
@@ -235,23 +235,23 @@ public function withUserInfo(Stringable|string|null $user, Stringable|string|nul
235235
}
236236

237237
if ($this->uri instanceof WhatWgUrl) {
238-
if (null !== $user) {
239-
$user = (string) $user;
238+
if (null !== $username) {
239+
$username = (string) $username;
240240
}
241241

242242
if (null !== $password) {
243243
$password = (string) $password;
244244
}
245245

246-
return new static($this->uri->withUsername($user)->withPassword($password));
246+
return new static($this->uri->withUsername($username)->withPassword($password));
247247
}
248248

249-
if (null == $user && $this->uri instanceof Psr7UriInterface) {
250-
$user = '';
249+
if (null == $username && $this->uri instanceof Psr7UriInterface) {
250+
$username = '';
251251
}
252252

253253
return new static($this->uri->withUserInfo(
254-
$user instanceof Stringable ? (string) $user : $user,
254+
$username instanceof Stringable ? (string) $username : $username,
255255
$password instanceof Stringable ? (string) $password : $password,
256256
));
257257
}

docs/components/7.0/modifiers.md

Lines changed: 168 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ echo Modifier::from($uriString)->mergeQuery($queryToMerge);
4848

4949
In addition to merging the query, `mergeQuery` has:
5050

51-
- enforced `RFC3986` encoding throughout the modifications;
51+
- enforced standard compliant encoding throughout the modifications;
5252
- not mangle your data during merging;
5353
- returned a valid URI object;
5454

@@ -114,6 +114,126 @@ $uri->toHtmlAnchor('My Shop', ['class' => ['text-center', 'text-6xl']]);
114114
<p class="message-info">The <code>toDisplayString()</code>, <code>toMarkdownAnchor()</code> and <code>toHtmlAnchor()</code> methods are available since version <code>7.6.0</code>.</p>
115115
<p class="message-notice">The <code>getUri()</code>, <code>getUriString()</code> and <code>getIdnUriString()</code> methods are deprecated since version <code>7.6.0</code>.</p>
116116

117+
## General Modifiers
118+
119+
<p class="message-notice">available since version <code>7.6.0</code></p>
120+
121+
With the addition of (2) two new native PHP URI representations, it can become complex to
122+
remember which URI method to use and which type of argument is expected. The `Modifier` can
123+
ease this by wrapping the underlying URI object is a common and predicable public API.
124+
125+
Apart from partially modifying an URI component, since version `7.6.0`, you can directly:
126+
127+
- completely change a URI component;
128+
- resolve URIs;
129+
- normalize URIs;
130+
131+
### Modifier complete URI component replacement
132+
133+
The `Modifier` class will perform some sanity checks and/or formatting before
134+
handing over the changed value to the underlying object to perform the action.
135+
Unless the input data is invalid, the exception thrown will be the ones from the
136+
underlying URI object.
137+
138+
Here's an example:
139+
140+
```php
141+
use Uri\Rfc3986\Uri;
142+
143+
echo new Uri('http://example.com/foo/bar')
144+
->withHost('bébé.be')
145+
->toString(), PHP_EOL;
146+
// this will throw because
147+
// the host contains unsupported characters
148+
// according to RFC3986
149+
```
150+
151+
In contrast, when using the `Modifier` the result is different:
152+
153+
```php
154+
use League\Uri\Modifier;
155+
use Uri\Rfc3986\Uri;
156+
157+
echo Modifier::from(new Uri('http://example.com/foo/bar'))
158+
->withHost('bébé.be')
159+
->uri()
160+
->toString(), PHP_EOL;
161+
// the `uri()` methods returns a valid Uri\Rfc3986\Uri instance
162+
// its `toString()` method returns http://xn--bb-bjab.be/foo/bar
163+
// the modifier has converted the host into its ascii representation
164+
// to avoid the exception to be thrown.
165+
```
166+
167+
### URI resolution
168+
169+
Apart from modifying a URI component, the `Modifier` can also normalize or
170+
resolve URI. Resolving and Normalizing URI is supported by `League\Uri\Uri`,
171+
and PHP's native URI object **but** not by PSR-7 `UriInterface` and the
172+
public API diverge. using the `Modifier` class you get a single method for
173+
all the URI objects and add the missing support for any PSR-7 implementing class
174+
175+
```php
176+
use Uri\Whatwg\Url;
177+
178+
echo new Url('http://example.com/foo/bar')
179+
->resolve('./../bar')
180+
->toAsciiString(), PHP_EOL;
181+
// returns http://example.com/bar
182+
// there is no equivalent in PSR-7
183+
```
184+
using the `Modifier` you can do the following:
185+
186+
```php
187+
use League\Uri\Modifier;
188+
use GuzzleHttp\Psr7\Utils;
189+
190+
echo Modifier::from(Utils::uriFor('http://example.com/foo/bar'))
191+
->resolve('./../bar')
192+
->uri()
193+
->__toString(), PHP_EOL;
194+
// `uri()` returns a Guzzle PSR-7 URI object
195+
// returns "http://example.com/bar"
196+
```
197+
198+
### URI normalization
199+
200+
RFC3986 and WHATWG URL specification both allow normalizing URIs. But both
201+
specification do it in a different way and capacity. Normalization is
202+
mandatory when using a WHATWG URL but optional with RFC3986. It is
203+
not covered in PSR-7. Which again may leave the developer in a challenging
204+
situation. To ease developer experience, the `Modifier` class exposes a
205+
new `normalize` method which guarantee normalization regardless of the
206+
underlying URI object.
207+
208+
```php
209+
use League\Uri\Url;
210+
use Uri\Rfc3986\Uri as Rfc3986Uri;
211+
use Uri\Whatwg\Url as WhatwgUrl;
212+
213+
$uriString = 'HttP://ExamPle.com/./../foo/bar';
214+
echo (new WhatwgUrl($uriString))->toAsciiString(), PHP_EOL;
215+
echo (new Rfc3986Uri($uriString))->toString(), PHP_EOL;
216+
echo Uri::new($uriString)->normalize()->toString(), PHP_EOL;
217+
// returns 'http://example.com/foo/bar
218+
// PSR-7 UriInterface does not have a method for that
219+
```
220+
221+
Again using the `Modifier` class you will get a unified and predicable returned URI
222+
223+
```php
224+
use League\Uri\Modifier;
225+
use GuzzleHttp\Psr7\Utils;
226+
227+
$uriString = 'HttP://ExamPle.com/./../foo/bar';
228+
echo Modifier::from(Utils::uriFor($uriString))
229+
->normalize()
230+
->uri()
231+
->__toString();
232+
// returns 'http://example.com/foo/bar
233+
```
234+
235+
## Partial Modifiers
236+
117237
### Available modifiers
118238

119239
Under the hood the `Modifier` class intensively uses the [URI components objects](/components/7.0/)
@@ -202,12 +322,10 @@ to apply the following changes to the submitted URI.
202322
<li><a href="#modifierwithscheme">withScheme</a></li>
203323
<li><a href="#modifierwithuserinfo">withUserInfo</a></li>
204324
<li><a href="#modifierwithport">withPort</a></li>
205-
<li><a href="#modifierresovlve">URI resolve</a></li>
206325
</ul>
207326
</div>
208327
</div>
209328

210-
211329
## Query Modifiers
212330

213331
Following modifiers update and normalize the URI query component.
@@ -1086,42 +1204,59 @@ echo Modifier::from($uri)
10861204
// display ":~:text=foo,bar&text=yes"
10871205
~~~
10881206

1089-
## General modifications
1207+
## Other available modifiers
1208+
1209+
### Modifier::withUserInfo
10901210

10911211
<p class="message-notice">available since version <code>7.6.0</code></p>
10921212

1093-
To ease modifying URI since version `7.6.0` you can directly access:
1213+
Allow modifying the user info component
10941214

1095-
- the modifier methods from the underlying URI object or
1096-
- resolve an URI base on the underlying URI object rules or
1097-
- normalize an URI base on the underlying URI object rules.
1215+
~~~php
1216+
use League\Uri\Modifier;
1217+
use Uri\Rfc3986\Uri;
10981218

1099-
The difference being that the `Modifier` class will perform the correct conversion
1100-
to handle the differences between URI object signature.
1219+
$uri = new Uri("http://www.example.com/path/to/the/sky");
1220+
echo Modifier::from($uri)
1221+
->withUserInfo(username: null, password: 'pa@ss')
1222+
->uri()
1223+
->getUserInfo();
1224+
// display ":pa%40ss"
1225+
// for information the Uri::withUserInfo method only takes a single variable.
1226+
~~~
11011227

1102-
```php
1228+
### Modifier::withScheme
1229+
1230+
<p class="message-notice">available since version <code>7.6.0</code></p>
1231+
1232+
Allow modifying the URI scheme
1233+
1234+
~~~php
1235+
use League\Uri\Modifier;
1236+
use Uri\Rfc3986\Uri;
1237+
1238+
$uri = new Uri("http://www.example.com/path/to/the/sky");
1239+
$newUri = Modifier::from($uri)->withScheme('HtTp')->uri();
1240+
$newUri->getRawScheme(); // returns 'HtTp'
1241+
$newUri->getScheme(); // returns 'http'
1242+
~~~
1243+
1244+
The stored scheme value will depend on the underlying URI object.
1245+
1246+
### Modifier::withPort
1247+
1248+
<p class="message-notice">available since version <code>7.6.0</code></p>
1249+
1250+
Allow modifying the URI port. Added for completeness. This
1251+
method works the same across all the URI objects, but may throw
1252+
depending on the restriction from the underlying URI object on
1253+
port range.
1254+
1255+
~~~php
11031256
use League\Uri\Modifier;
11041257
use Uri\WhatWg\Url;
11051258

1106-
$foo = '';
1107-
echo Modifier::from('http://bébé.be')
1108-
->when(
1109-
'' !== $foo,
1110-
fn (Modifier $uri) => $uri->withQuery('fname=jane&lname=Doe'), //on true
1111-
fn (Modifier $uri) => $uri->mergeQueryParameters(['fname' => 'john', 'lname' => 'Doe']), //on false
1112-
)
1113-
->appendSegment('toto')
1114-
->addRootLabel()
1115-
->prependLabel('shop')
1116-
->appendQuery('foo=toto&foo=tata')
1117-
->withFragment('chapter1')
1118-
->toDisplayString();
1119-
// returns 'http://shop.bébé.be./toto?fname=john&lname=Doe&foo=toto&foo=tata#chapter1';
1120-
1121-
echo Modifier::from(new Url('http://bébé.be/../do/it'))
1122-
->appendSegment('toto')
1123-
->resolve('./foo/../bar')
1124-
->uri()
1125-
->toAsciiString(), PHP_EOL;
1126-
// returns http://xn--bb-bjab.be/do/it/bar
1127-
```
1259+
$uri = new Url("http://www.example.com/path/to/the/sky");
1260+
$newUri = Modifier::from($uri)->withPort(433)->uri();
1261+
$newUri->getPort(); // returns 433
1262+
~~~

0 commit comments

Comments
 (0)