Skip to content

Commit

Permalink
Adding the extension page to the documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Nov 17, 2024
1 parent 8ef4a01 commit ed8eaa8
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 7 deletions.
6 changes: 3 additions & 3 deletions docs/00-intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ Once installed you will be able to do the following:
use Bakame\Http\StructuredFields\DataType;

$fieldValue = 'text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8';
$field = DataType::List->parse($fieldValue);
$field[1]->value()->toString(); // returns 'application/xhtml+xml'
$field[1]->parameterByKey(key: 'q', default: 1.0); // returns 1.0 if the parameter is not defined
$container = DataType::List->parse($fieldValue);
$container[1]->value()->toString(); // returns 'application/xhtml+xml'
$container[1]->parameterByKey(key: 'q', default: 1.0); // returns 1.0 if the parameter is not defined
```

## Motivation
Expand Down
2 changes: 2 additions & 0 deletions docs/01-basic-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ $permissions['picture-in-picture']->isEmpty(); // returns true because the list
count($permissions['geolocation']); // returns 2 the 'geolocation' feature has 2 values associated to it via a list
$permissions['geolocation'][-1]->value(); // returns the last value of the list 'https://example.com/'
$permissions['camera']->value(); // returns '*' the sole value attached to the 'camera' feature
isset($permissions['yolo']); // returns false this permission does not exust
$permissions->isEmpty(); // returns false the dictionary contains some permissions
```

> [!WARNING]
Expand Down
2 changes: 1 addition & 1 deletion docs/02-parsing-serializing.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ $permissions['picture-in-picture']->isEmpty(); // picture-in-picture returned va
count($permissions['geolocation']); // geolocation returned value is an InnerList of 3 Items
$permissions['geolocation'][1]->value(); // returns "https://example.com/"
$permissions['camera']->value(); // camera only value is a single Item
$permissions->getByIndex(2); // returns a tuple as n array ['camera', Item::fromPair(['*', []])]
$permissions->getByIndex(2); // returns an array ['camera', Item::fromPair(['*', []])]
```

In the example above:
Expand Down
2 changes: 1 addition & 1 deletion docs/03-value-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,4 @@ $displayString->type(); // returns Type::DisplayString
> Values are not directly accessible. They can only be retrieved from an Item
> Data type.
← [Parsing and Serializing](02-parsing-serializing.md) | [Item API](04-item.md) →
← [Parsing and Serializing](02-parsing-serializing.md) | [Item](04-item.md) →
5 changes: 5 additions & 0 deletions docs/04-item.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,8 @@ By default, you can access the member `Item` of a parameters using the following
- `Item::parameters` returns a `Parameters` instance;
- `Item::parameterByKey` returns the value of the bare item instance attached to the supplied `key`;
- `Item::parameterByIndex` returns the value of the bare item instance attached to the supplied `index`;

It is possible to alter and modify the `Parameters` attached to an `Item` but this section
will be explored in the next section about the containers.

← [Value Types](03-value-types.md) | [Containers](05-containers.md) →
2 changes: 1 addition & 1 deletion docs/05-containers.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,4 +457,4 @@ echo InnerList::new('foo', 'bar')
// ("foo" "bar");expire=@1681538756;path="/";max-age=2500
```

← [Item](04-item.md)
← [Item](04-item.md) | [Validation](06-validation.md) →
2 changes: 1 addition & 1 deletion docs/06-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,4 +427,4 @@ class it becomes easier to reuse it to validate your data.
To show how this can be achieved you can check the codebase from [HTTP Cache Status](https://github.com/bakame-php/http-cache-status)

← [Containers](05-containers.md)
← [Containers](05-containers.md) | [Extending the package functionalities](07-extensions.md)
102 changes: 102 additions & 0 deletions docs/07-extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Interacting with PHP ecosystem

All Datatype expose the `Stringable` interface while it is recommended to use
the `toHttpValue` method for better granularity. Supporting the `Stringable`
interface allows the package to easily interface with packages and frameworks
which expects a string or a stringable object when adding or updating
HTTP field values.

```php
$container = InnerList::new(ByteSequence::fromDecoded('Hello World'), 42.0, 42);

$container->toHttpValue(); // returns '(:SGVsbG8gV29ybGQ=: 42.0 42)'
echo $container; // returns '(:SGVsbG8gV29ybGQ=: 42.0 42)'
```

## Everything is final

As a rule of thumb all the classes from this package are final and immutable and
expose no particular interface.

> [!IMPORTANT]
> The `StructuredField` interface should be seen as an internal implementation detail
> and should not be implemented outside the package. While PHP does not prohibit such
> action, **you MUST NOT implement the `StructuredField` interface.**
The reason for disallowing the `StructuredField` interface is simple. We want to ensure
that in any situation the RFC is being respected. The contract is between the RFC and your
code the package only acts as a link between both parties.

## Closed for extension opened for composition

On the other hand to allow composition the package does expose the `StructuredFieldProvider` interface.

```php
interface StructuredFieldProvider
{
/**
* Returns an object implementing the StructuredField interface.
*/
public function toStructuredField(): StructuredField;
}
```

This interface should return one of the DataType class and this is the interface that needs
to be implemented. All the containers are able to work with a `StructuredFieldProvider`.

Imagine you have an `AcceptHeaderItem` class and you want to take advantage of the package. You
only have to implemente the `StructuredFieldProvider`. Once done, your class will be able to
work with the `OuterList` class.

```php
class readonly AcceptHeaderItem
{
public function __construct(
public string $value;
public float $quality = 1.0;
) {}
}
```

To use the package you will have to add the missing interface

```php
class readonly AcceptHeaderItem implements StructuredFieldProvider
{
public function __construct(
public string $value,
public float $quality = 1.0
) {}

public function toStructuredField(): StructuredField
{
return Item::fromToken($this->value)
->withParameters(
Parameters::new()
->append('q', $this->quality)
->filter(fn (array $pair): bool => $pair[0] !== 'q' || 1.0 !== $pair[1]->value())
);
}
}
```

Now this class can be used with the `OuterList` class to properly serialize an `Accept` header
as mandated by the RFC.

```php
$json = new AcceptHeaderItem('application/json');
$csv = new AcceptHeaderItem('text/csv', 0.7);

echo OuterList::new($json, $csv);
//returns application/json, text/csv;q=0.7
```

In the example provided we added the interface on the class itself but of course you are free to use
a different approach, as long as you end up have a class that implements the `StructuredFieldProvider`
contract.

To show how this can be achieved you can check the codebase from [HTTP Cache Status](https://github.com/bakame-php/http-cache-status)
which uses the interface. Of note by using this interface you can completely hide the presence of
this package to your end users if needed.

← [Validation](06-validation.md)

0 comments on commit ed8eaa8

Please sign in to comment.